-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
routing.go
112 lines (89 loc) · 2.75 KB
/
routing.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
package routing
import (
"context"
"time"
"github.com/libp2p/go-libp2p/core/discovery"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/libp2p/go-libp2p/core/routing"
"github.com/ipfs/go-cid"
mh "github.com/multiformats/go-multihash"
)
// RoutingDiscovery is an implementation of discovery using ContentRouting.
// Namespaces are translated to Cids using the SHA256 hash.
type RoutingDiscovery struct {
routing.ContentRouting
}
func NewRoutingDiscovery(router routing.ContentRouting) *RoutingDiscovery {
return &RoutingDiscovery{router}
}
func (d *RoutingDiscovery) Advertise(ctx context.Context, ns string, opts ...discovery.Option) (time.Duration, error) {
var options discovery.Options
err := options.Apply(opts...)
if err != nil {
return 0, err
}
ttl := options.Ttl
if ttl == 0 || ttl > 3*time.Hour {
// the DHT provider record validity is 24hrs, but it is recommended to republish at least every 6hrs
// we go one step further and republish every 3hrs
ttl = 3 * time.Hour
}
cid, err := nsToCid(ns)
if err != nil {
return 0, err
}
// this context requires a timeout; it determines how long the DHT looks for
// closest peers to the key/CID before it goes on to provide the record to them.
// Not setting a timeout here will make the DHT wander forever.
pctx, cancel := context.WithTimeout(ctx, 60*time.Second)
defer cancel()
err = d.Provide(pctx, cid, true)
if err != nil {
return 0, err
}
return ttl, nil
}
func (d *RoutingDiscovery) FindPeers(ctx context.Context, ns string, opts ...discovery.Option) (<-chan peer.AddrInfo, error) {
var options discovery.Options
err := options.Apply(opts...)
if err != nil {
return nil, err
}
limit := options.Limit
if limit == 0 {
limit = 100 // that's just arbitrary, but FindProvidersAsync needs a count
}
cid, err := nsToCid(ns)
if err != nil {
return nil, err
}
return d.FindProvidersAsync(ctx, cid, limit), nil
}
func nsToCid(ns string) (cid.Cid, error) {
h, err := mh.Sum([]byte(ns), mh.SHA2_256, -1)
if err != nil {
return cid.Undef, err
}
return cid.NewCidV1(cid.Raw, h), nil
}
func NewDiscoveryRouting(disc discovery.Discovery, opts ...discovery.Option) *DiscoveryRouting {
return &DiscoveryRouting{disc, opts}
}
type DiscoveryRouting struct {
discovery.Discovery
opts []discovery.Option
}
func (r *DiscoveryRouting) Provide(ctx context.Context, c cid.Cid, bcast bool) error {
if !bcast {
return nil
}
_, err := r.Advertise(ctx, cidToNs(c), r.opts...)
return err
}
func (r *DiscoveryRouting) FindProvidersAsync(ctx context.Context, c cid.Cid, limit int) <-chan peer.AddrInfo {
ch, _ := r.FindPeers(ctx, cidToNs(c), append([]discovery.Option{discovery.Limit(limit)}, r.opts...)...)
return ch
}
func cidToNs(c cid.Cid) string {
return "/provider/" + c.String()
}