Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 88db4f3

Browse files
committedMar 8, 2024··
wip?
1 parent 156dc1e commit 88db4f3

File tree

3 files changed

+178
-6
lines changed

3 files changed

+178
-6
lines changed
 

‎examples/gateway/proxy/main_test.go

+2-4
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,7 @@ import (
99
"strings"
1010
"testing"
1111

12-
"github.com/ipfs/boxo/blockservice"
1312
"github.com/ipfs/boxo/examples/gateway/common"
14-
"github.com/ipfs/boxo/exchange/offline"
1513
"github.com/ipfs/boxo/gateway"
1614
blocks "github.com/ipfs/go-block-format"
1715
"github.com/stretchr/testify/assert"
@@ -25,10 +23,10 @@ const (
2523
func newProxyGateway(t *testing.T, rs *httptest.Server) *httptest.Server {
2624
blockStore, err := gateway.NewProxyBlockstore([]string{rs.URL}, nil)
2725
require.NoError(t, err)
28-
blockService := blockservice.New(blockStore, offline.Exchange(blockStore))
26+
// blockService := blockservice.New(blockStore, offline.Exchange(blockStore))
2927
routing := newProxyRouting(rs.URL, nil)
3028

31-
backend, err := gateway.NewBlocksBackend(blockService, gateway.WithValueStore(routing))
29+
backend, err := gateway.NewGraphGatewayBackend(blockStore, gateway.WithValueStore(routing))
3230
require.NoError(t, err)
3331

3432
handler := common.NewHandler(backend)

‎gateway/backend_remote.go

+174
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,23 @@ import (
99
"sync"
1010
"time"
1111

12+
bsfetcher "github.com/ipfs/boxo/fetcher/impl/blockservice"
1213
"github.com/ipfs/boxo/verifcid"
1314
blocks "github.com/ipfs/go-block-format"
1415
"github.com/ipfs/go-cid"
1516
"github.com/ipfs/go-unixfsnode"
17+
"github.com/ipfs/go-unixfsnode/data"
1618
"github.com/ipld/go-car"
19+
dagpb "github.com/ipld/go-codec-dagpb"
1720
"github.com/ipld/go-ipld-prime"
1821
"github.com/ipld/go-ipld-prime/datamodel"
1922
"github.com/ipld/go-ipld-prime/linking"
2023
cidlink "github.com/ipld/go-ipld-prime/linking/cid"
24+
"github.com/ipld/go-ipld-prime/node/basicnode"
25+
"github.com/ipld/go-ipld-prime/schema"
26+
"github.com/ipld/go-ipld-prime/traversal"
27+
"github.com/ipld/go-ipld-prime/traversal/selector"
28+
selectorparse "github.com/ipld/go-ipld-prime/traversal/selector/parse"
2129
"github.com/multiformats/go-multihash"
2230
)
2331

@@ -135,3 +143,169 @@ func getLinksystem(fn getBlock) *ipld.LinkSystem {
135143
unixfsnode.AddUnixFSReificationToLinkSystem(&lsys)
136144
return &lsys
137145
}
146+
147+
// walkGatewaySimpleSelector2 walks the subgraph described by the path and terminal element parameters
148+
func walkGatewaySimpleSelector2(ctx context.Context, terminalBlk blocks.Block, dagScope DagScope, entityRange *DagByteRange, lsys *ipld.LinkSystem) error {
149+
lctx := ipld.LinkContext{Ctx: ctx}
150+
var err error
151+
152+
// If the scope is the block, we only need the root block of the last element of the path, which we have.
153+
if dagScope == DagScopeBlock {
154+
return nil
155+
}
156+
157+
// decode the terminal block into a node
158+
pc := dagpb.AddSupportToChooser(func(lnk ipld.Link, lnkCtx ipld.LinkContext) (ipld.NodePrototype, error) {
159+
if tlnkNd, ok := lnkCtx.LinkNode.(schema.TypedLinkNode); ok {
160+
return tlnkNd.LinkTargetNodePrototype(), nil
161+
}
162+
return basicnode.Prototype.Any, nil
163+
})
164+
165+
pathTerminalCidLink := cidlink.Link{Cid: terminalBlk.Cid()}
166+
np, err := pc(pathTerminalCidLink, lctx)
167+
if err != nil {
168+
return err
169+
}
170+
171+
decoder, err := lsys.DecoderChooser(pathTerminalCidLink)
172+
if err != nil {
173+
return err
174+
}
175+
nb := np.NewBuilder()
176+
blockData := terminalBlk.RawData()
177+
if err := decoder(nb, bytes.NewReader(blockData)); err != nil {
178+
return err
179+
}
180+
lastCidNode := nb.Build()
181+
182+
// TODO: Evaluate:
183+
// Does it matter that we're ignoring the "remainder" portion of the traversal in GetCAR?
184+
// Does it matter that we're using a linksystem with the UnixFS reifier for dagscope=all?
185+
186+
// If we're asking for everything then give it
187+
if dagScope == DagScopeAll {
188+
sel, err := selector.ParseSelector(selectorparse.CommonSelector_ExploreAllRecursively)
189+
if err != nil {
190+
return err
191+
}
192+
193+
progress := traversal.Progress{
194+
Cfg: &traversal.Config{
195+
Ctx: ctx,
196+
LinkSystem: *lsys,
197+
LinkTargetNodePrototypeChooser: bsfetcher.DefaultPrototypeChooser,
198+
LinkVisitOnlyOnce: false, // Despite being safe for the "all" selector we do this walk anyway since this is how we will be receiving the blocks
199+
},
200+
}
201+
202+
if err := progress.WalkMatching(lastCidNode, sel, func(progress traversal.Progress, node datamodel.Node) error {
203+
return nil
204+
}); err != nil {
205+
return err
206+
}
207+
return nil
208+
}
209+
210+
// From now on, dag-scope=entity!
211+
// Since we need more of the graph load it to figure out what we have
212+
// This includes determining if the terminal node is UnixFS or not
213+
if pbn, ok := lastCidNode.(dagpb.PBNode); !ok {
214+
// If it's not valid dag-pb then we're done
215+
return nil
216+
} else if !pbn.FieldData().Exists() {
217+
// If it's not valid UnixFS then we're done
218+
return nil
219+
} else if unixfsFieldData, decodeErr := data.DecodeUnixFSData(pbn.Data.Must().Bytes()); decodeErr != nil {
220+
// If it's not valid dag-pb and UnixFS then we're done
221+
return nil
222+
} else {
223+
switch unixfsFieldData.FieldDataType().Int() {
224+
case data.Data_Directory, data.Data_Symlink:
225+
// These types are non-recursive so we're done
226+
return nil
227+
case data.Data_Raw, data.Data_Metadata:
228+
// TODO: for now, we decided to return nil here. The different implementations are inconsistent
229+
// and UnixFS is not properly specified: https://github.com/ipfs/specs/issues/316.
230+
// - Is Data_Raw different from Data_File?
231+
// - Data_Metadata is handled differently in boxo/ipld/unixfs and go-unixfsnode.
232+
return nil
233+
case data.Data_HAMTShard:
234+
// Return all elements in the map
235+
_, err := lsys.KnownReifiers["unixfs-preload"](lctx, lastCidNode, lsys)
236+
if err != nil {
237+
return err
238+
}
239+
return nil
240+
case data.Data_File:
241+
nd, err := unixfsnode.Reify(lctx, lastCidNode, lsys)
242+
if err != nil {
243+
return err
244+
}
245+
246+
fnd, ok := nd.(datamodel.LargeBytesNode)
247+
if !ok {
248+
return fmt.Errorf("could not process file since it did not present as large bytes")
249+
}
250+
f, err := fnd.AsLargeBytes()
251+
if err != nil {
252+
return err
253+
}
254+
255+
// Get the entity range. If it's empty, assume the defaults (whole file).
256+
effectiveRange := entityRange
257+
if effectiveRange == nil {
258+
effectiveRange = &DagByteRange{
259+
From: 0,
260+
}
261+
}
262+
263+
from := effectiveRange.From
264+
265+
// If we're starting to read based on the end of the file, find out where that is.
266+
var fileLength int64
267+
foundFileLength := false
268+
if effectiveRange.From < 0 {
269+
fileLength, err = f.Seek(0, io.SeekEnd)
270+
if err != nil {
271+
return err
272+
}
273+
from = fileLength + effectiveRange.From
274+
foundFileLength = true
275+
}
276+
277+
// If we're reading until the end of the file then do it
278+
if effectiveRange.To == nil {
279+
if _, err := f.Seek(from, io.SeekStart); err != nil {
280+
return err
281+
}
282+
_, err = io.Copy(io.Discard, f)
283+
return err
284+
}
285+
286+
to := *effectiveRange.To
287+
if (*effectiveRange.To) < 0 && !foundFileLength {
288+
fileLength, err = f.Seek(0, io.SeekEnd)
289+
if err != nil {
290+
return err
291+
}
292+
to = fileLength + *effectiveRange.To
293+
foundFileLength = true
294+
}
295+
296+
numToRead := 1 + to - from
297+
if numToRead < 0 {
298+
return fmt.Errorf("tried to read less than zero bytes")
299+
}
300+
301+
if _, err := f.Seek(from, io.SeekStart); err != nil {
302+
return err
303+
}
304+
_, err = io.CopyN(io.Discard, f, numToRead)
305+
return err
306+
default:
307+
// Not a supported type, so we're done
308+
return nil
309+
}
310+
}
311+
}

‎gateway/backend_remote_2.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -1108,7 +1108,7 @@ func (api *GraphGateway) GetCAR(ctx context.Context, p path.ImmutablePath, param
11081108
l := getLinksystem(teeBlock)
11091109

11101110
// First resolve the path since we always need to.
1111-
_, terminalCid, remainder, _, err := resolvePathWithRootsAndBlock(ctx, p, l)
1111+
_, terminalCid, remainder, terminalBlk, err := resolvePathWithRootsAndBlock(ctx, p, l)
11121112
if err != nil {
11131113
return err
11141114
}
@@ -1133,7 +1133,7 @@ func (api *GraphGateway) GetCAR(ctx context.Context, p path.ImmutablePath, param
11331133
blockBuffer = nil
11341134
}
11351135

1136-
err = walkGatewaySimpleSelector(ctx, terminalCid, remainder, params, l)
1136+
err = walkGatewaySimpleSelector2(ctx, terminalBlk, params.Scope, params.Range, l)
11371137
if err != nil {
11381138
return err
11391139
}

0 commit comments

Comments
 (0)
Please sign in to comment.