|
| 1 | +package mdutils |
| 2 | + |
| 3 | +import ( |
| 4 | + "context" |
| 5 | + "fmt" |
| 6 | + |
| 7 | + blocks "github.com/ipfs/go-block-format" |
| 8 | + "github.com/ipfs/go-cid" |
| 9 | + format "github.com/ipfs/go-ipld-format" |
| 10 | + |
| 11 | + "github.com/ipfs/boxo/ipld/merkledag" |
| 12 | +) |
| 13 | + |
| 14 | +// NewDAGGenerator returns an object capable of |
| 15 | +// producing IPLD DAGs. |
| 16 | +func NewDAGGenerator() *DAGGenerator { |
| 17 | + return &DAGGenerator{} |
| 18 | +} |
| 19 | + |
| 20 | +// DAGGenerator generates BasicBlocks on demand. |
| 21 | +// For each instance of DAGGenerator, each new DAG is different from the |
| 22 | +// previous, although two different instances will produce the same, given the |
| 23 | +// same parameters. |
| 24 | +type DAGGenerator struct { |
| 25 | + seq int |
| 26 | +} |
| 27 | + |
| 28 | +// MakeDagBlock generate a balanced DAG with the given fanout and depth, and add the blocks to the adder. |
| 29 | +// This adder can be for example a blockstore.Put or a blockservice.AddBlock. |
| 30 | +func (dg *DAGGenerator) MakeDagBlock(adder func(ctx context.Context, block blocks.Block) error, fanout uint, depth uint) (c cid.Cid, allCids []cid.Cid, err error) { |
| 31 | + return dg.MakeDagNode(func(ctx context.Context, node format.Node) error { |
| 32 | + return adder(ctx, node.(blocks.Block)) |
| 33 | + }, fanout, depth) |
| 34 | +} |
| 35 | + |
| 36 | +// MakeDagNode generate a balanced DAG with the given fanout and depth, and add the blocks to the adder. |
| 37 | +// This adder can be for example a DAGService.Add. |
| 38 | +func (dg *DAGGenerator) MakeDagNode(adder func(ctx context.Context, node format.Node) error, fanout uint, depth uint) (c cid.Cid, allCids []cid.Cid, err error) { |
| 39 | + c, _, allCids, err = dg.generate(adder, fanout, depth) |
| 40 | + return c, allCids, err |
| 41 | +} |
| 42 | + |
| 43 | +func (dg *DAGGenerator) generate(adder func(ctx context.Context, node format.Node) error, fanout uint, depth uint) (c cid.Cid, size uint64, allCids []cid.Cid, err error) { |
| 44 | + if depth == 0 { |
| 45 | + panic("depth should be at least 1") |
| 46 | + } |
| 47 | + if depth == 1 { |
| 48 | + c, size, err = dg.encodeBlock(adder) |
| 49 | + if err != nil { |
| 50 | + return cid.Undef, 0, nil, err |
| 51 | + } |
| 52 | + return c, size, []cid.Cid{c}, nil |
| 53 | + } |
| 54 | + links := make([]*format.Link, fanout) |
| 55 | + for i := uint(0); i < fanout; i++ { |
| 56 | + root, size, children, err := dg.generate(adder, fanout, depth-1) |
| 57 | + if err != nil { |
| 58 | + return cid.Undef, 0, nil, err |
| 59 | + } |
| 60 | + links[i] = &format.Link{Cid: root, Size: size} |
| 61 | + allCids = append(allCids, children...) |
| 62 | + } |
| 63 | + c, size, err = dg.encodeBlock(adder, links...) |
| 64 | + if err != nil { |
| 65 | + return cid.Undef, 0, nil, err |
| 66 | + } |
| 67 | + return c, size, append([]cid.Cid{c}, allCids...), nil |
| 68 | +} |
| 69 | + |
| 70 | +func (dg *DAGGenerator) encodeBlock(adder func(ctx context.Context, node format.Node) error, links ...*format.Link) (cid.Cid, uint64, error) { |
| 71 | + dg.seq++ |
| 72 | + nd := &merkledag.ProtoNode{} |
| 73 | + nd.SetData([]byte(fmt.Sprint(dg.seq))) |
| 74 | + for i, link := range links { |
| 75 | + err := nd.AddRawLink(fmt.Sprintf("link-%d", i), link) |
| 76 | + if err != nil { |
| 77 | + return cid.Undef, 0, err |
| 78 | + } |
| 79 | + } |
| 80 | + err := adder(context.Background(), nd) |
| 81 | + if err != nil { |
| 82 | + return cid.Undef, 0, err |
| 83 | + } |
| 84 | + size, err := nd.Size() |
| 85 | + return nd.Cid(), size, err |
| 86 | +} |
0 commit comments