daghelpers.go 1.6 KB
Newer Older
1 2 3 4 5 6 7 8 9
package format

import (
	"context"

	cid "github.com/ipfs/go-cid"
)

// GetDAG will fill out all of the links of the given Node.
10 11
// It returns an array of NodePromise with the linked nodes all in the proper
// order.
12
func GetDAG(ctx context.Context, ds DAGService, root Node) []*NodePromise {
13 14 15 16 17 18 19 20 21 22
	var cids []*cid.Cid
	for _, lnk := range root.Links() {
		cids = append(cids, lnk.Cid)
	}

	return GetNodes(ctx, ds, cids)
}

// GetNodes returns an array of 'FutureNode' promises, with each corresponding
// to the key with the same index as the passed in keys
23
func GetNodes(ctx context.Context, ds DAGService, keys []*cid.Cid) []*NodePromise {
24 25 26 27 28 29

	// Early out if no work to do
	if len(keys) == 0 {
		return nil
	}

30
	promises := make([]*NodePromise, len(keys))
31
	for i := range keys {
32
		promises[i] = NewNodePromise(ctx)
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
	}

	dedupedKeys := dedupeKeys(keys)
	go func() {
		ctx, cancel := context.WithCancel(ctx)
		defer cancel()

		nodechan := ds.GetMany(ctx, dedupedKeys)

		for count := 0; count < len(keys); {
			select {
			case opt, ok := <-nodechan:
				if !ok {
					for _, p := range promises {
						p.Fail(ErrNotFound)
					}
					return
				}

				if opt.Err != nil {
					for _, p := range promises {
						p.Fail(opt.Err)
					}
					return
				}

				nd := opt.Node
Steven Allen's avatar
Steven Allen committed
60 61 62 63 64 65
				c := nd.Cid()
				for i, lnk_c := range keys {
					if c.Equals(lnk_c) {
						count++
						promises[i].Send(nd)
					}
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
				}
			case <-ctx.Done():
				return
			}
		}
	}()
	return promises
}

// Remove duplicates from a list of keys
func dedupeKeys(cids []*cid.Cid) []*cid.Cid {
	set := cid.NewSet()
	for _, c := range cids {
		set.Add(c)
	}
	return set.Keys()
}