@cryptotaxi247 / kubo / commits / 80973d87c

core: deprecate CoreAPI.Dht, introduce CoreAPI.Routing

Henrique Dias committed Jan 31, 2024 at 11:07 UTC 80973d87ccc189b3a23b01c1f02dbca4a840b462
18 files changed +541 -470
client/rpc/api.go
+2
@@ -227,6 +227,8 @@ func (api *HttpApi) Object() iface.ObjectAPI {
227 return (*ObjectAPI)(api)
228 }
229
230 +// nolint deprecated
231 +// Deprecated: use [HttpApi.Routing] instead.
232 func (api *HttpApi) Dht() iface.DhtAPI {
233 return (*DhtAPI)(api)
234 }
client/rpc/dht.go
+9 -89
@@ -2,110 +2,30 @@ package rpc
2
3 import (
4 "context"
5 - "encoding/json"
5
6 "github.com/ipfs/boxo/path"
7 caopts "github.com/ipfs/kubo/core/coreiface/options"
8 "github.com/libp2p/go-libp2p/core/peer"
10 - "github.com/libp2p/go-libp2p/core/routing"
9 )
10
11 type DhtAPI HttpApi
12
13 +// nolint deprecated
14 +// Deprecated: use [RoutingAPI.FindPeer] instead.
15 func (api *DhtAPI) FindPeer(ctx context.Context, p peer.ID) (peer.AddrInfo, error) {
16 - var out struct {
17 - Type routing.QueryEventType
18 - Responses []peer.AddrInfo
19 - }
20 - resp, err := api.core().Request("dht/findpeer", p.String()).Send(ctx)
21 - if err != nil {
22 - return peer.AddrInfo{}, err
23 - }
24 - if resp.Error != nil {
25 - return peer.AddrInfo{}, resp.Error
26 - }
27 - defer resp.Close()
28 - dec := json.NewDecoder(resp.Output)
29 - for {
30 - if err := dec.Decode(&out); err != nil {
31 - return peer.AddrInfo{}, err
32 - }
33 - if out.Type == routing.FinalPeer {
34 - return out.Responses[0], nil
35 - }
36 - }
16 + return api.core().Routing().FindPeer(ctx, p)
17 }
18
19 +// nolint deprecated
20 +// Deprecated: use [RoutingAPI.FindProviders] instead.
21 func (api *DhtAPI) FindProviders(ctx context.Context, p path.Path, opts ...caopts.DhtFindProvidersOption) (<-chan peer.AddrInfo, error) {
40 - options, err := caopts.DhtFindProvidersOptions(opts...)
41 - if err != nil {
42 - return nil, err
43 - }
44 -
45 - rp, _, err := api.core().ResolvePath(ctx, p)
46 - if err != nil {
47 - return nil, err
48 - }
49 -
50 - resp, err := api.core().Request("dht/findprovs", rp.RootCid().String()).
51 - Option("num-providers", options.NumProviders).
52 - Send(ctx)
53 - if err != nil {
54 - return nil, err
55 - }
56 - if resp.Error != nil {
57 - return nil, resp.Error
58 - }
59 - res := make(chan peer.AddrInfo)
60 -
61 - go func() {
62 - defer resp.Close()
63 - defer close(res)
64 - dec := json.NewDecoder(resp.Output)
65 -
66 - for {
67 - var out struct {
68 - Extra string
69 - Type routing.QueryEventType
70 - Responses []peer.AddrInfo
71 - }
72 -
73 - if err := dec.Decode(&out); err != nil {
74 - return // todo: handle this somehow
75 - }
76 - if out.Type == routing.QueryError {
77 - return // usually a 'not found' error
78 - // todo: handle other errors
79 - }
80 - if out.Type == routing.Provider {
81 - for _, pi := range out.Responses {
82 - select {
83 - case res <- pi:
84 - case <-ctx.Done():
85 - return
86 - }
87 - }
88 - }
89 - }
90 - }()
91 -
92 - return res, nil
22 + return api.core().Routing().FindProviders(ctx, p, opts...)
23 }
24
25 +// nolint deprecated
26 +// Deprecated: use [RoutingAPI.Provide] instead.
27 func (api *DhtAPI) Provide(ctx context.Context, p path.Path, opts ...caopts.DhtProvideOption) error {
96 - options, err := caopts.DhtProvideOptions(opts...)
97 - if err != nil {
98 - return err
99 - }
100 -
101 - rp, _, err := api.core().ResolvePath(ctx, p)
102 - if err != nil {
103 - return err
104 - }
105 -
106 - return api.core().Request("dht/provide", rp.RootCid().String()).
107 - Option("recursive", options.Recursive).
108 - Exec(ctx, nil)
28 + return api.core().Routing().Provide(ctx, p, opts...)
29 }
30
31 func (api *DhtAPI) core() *HttpApi {
client/rpc/routing.go
+98
@@ -6,7 +6,9 @@ import (
6 "encoding/base64"
7 "encoding/json"
8
9 + "github.com/ipfs/boxo/path"
10 "github.com/ipfs/kubo/core/coreiface/options"
11 + "github.com/libp2p/go-libp2p/core/peer"
12 "github.com/libp2p/go-libp2p/core/routing"
13 )
14
@@ -58,6 +60,102 @@ func (api *RoutingAPI) Put(ctx context.Context, key string, value []byte, opts .
60 return nil
61 }
62
63 +func (api *RoutingAPI) FindPeer(ctx context.Context, p peer.ID) (peer.AddrInfo, error) {
64 + var out struct {
65 + Type routing.QueryEventType
66 + Responses []peer.AddrInfo
67 + }
68 + resp, err := api.core().Request("routing/findpeer", p.String()).Send(ctx)
69 + if err != nil {
70 + return peer.AddrInfo{}, err
71 + }
72 + if resp.Error != nil {
73 + return peer.AddrInfo{}, resp.Error
74 + }
75 + defer resp.Close()
76 + dec := json.NewDecoder(resp.Output)
77 + for {
78 + if err := dec.Decode(&out); err != nil {
79 + return peer.AddrInfo{}, err
80 + }
81 + if out.Type == routing.FinalPeer {
82 + return out.Responses[0], nil
83 + }
84 + }
85 +}
86 +
87 +func (api *RoutingAPI) FindProviders(ctx context.Context, p path.Path, opts ...options.RoutingFindProvidersOption) (<-chan peer.AddrInfo, error) {
88 + options, err := options.RoutingFindProvidersOptions(opts...)
89 + if err != nil {
90 + return nil, err
91 + }
92 +
93 + rp, _, err := api.core().ResolvePath(ctx, p)
94 + if err != nil {
95 + return nil, err
96 + }
97 +
98 + resp, err := api.core().Request("routing/findprovs", rp.RootCid().String()).
99 + Option("num-providers", options.NumProviders).
100 + Send(ctx)
101 + if err != nil {
102 + return nil, err
103 + }
104 + if resp.Error != nil {
105 + return nil, resp.Error
106 + }
107 + res := make(chan peer.AddrInfo)
108 +
109 + go func() {
110 + defer resp.Close()
111 + defer close(res)
112 + dec := json.NewDecoder(resp.Output)
113 +
114 + for {
115 + var out struct {
116 + Extra string
117 + Type routing.QueryEventType
118 + Responses []peer.AddrInfo
119 + }
120 +
121 + if err := dec.Decode(&out); err != nil {
122 + return // todo: handle this somehow
123 + }
124 + if out.Type == routing.QueryError {
125 + return // usually a 'not found' error
126 + // todo: handle other errors
127 + }
128 + if out.Type == routing.Provider {
129 + for _, pi := range out.Responses {
130 + select {
131 + case res <- pi:
132 + case <-ctx.Done():
133 + return
134 + }
135 + }
136 + }
137 + }
138 + }()
139 +
140 + return res, nil
141 +}
142 +
143 +func (api *RoutingAPI) Provide(ctx context.Context, p path.Path, opts ...options.RoutingProvideOption) error {
144 + options, err := options.RoutingProvideOptions(opts...)
145 + if err != nil {
146 + return err
147 + }
148 +
149 + rp, _, err := api.core().ResolvePath(ctx, p)
150 + if err != nil {
151 + return err
152 + }
153 +
154 + return api.core().Request("routing/provide", rp.RootCid().String()).
155 + Option("recursive", options.Recursive).
156 + Exec(ctx, nil)
157 +}
158 +
159 func (api *RoutingAPI) core() *HttpApi {
160 return (*HttpApi)(api)
161 }
core/coreapi/coreapi.go
+2 -1
@@ -130,7 +130,8 @@ func (api *CoreAPI) Pin() coreiface.PinAPI {
130 return (*PinAPI)(api)
131 }
132
133 -// Dht returns the DhtAPI interface implementation backed by the go-ipfs node
133 +// nolint deprecated
134 +// Deprecated: use [CoreAPI.Routing] instead.
135 func (api *CoreAPI) Dht() coreiface.DhtAPI {
136 return (*DhtAPI)(api)
137 }
core/coreapi/dht.go
+10 -130
@@ -2,151 +2,31 @@ package coreapi
2
3 import (
4 "context"
5 - "fmt"
5
7 - blockservice "github.com/ipfs/boxo/blockservice"
8 - blockstore "github.com/ipfs/boxo/blockstore"
9 - offline "github.com/ipfs/boxo/exchange/offline"
10 - dag "github.com/ipfs/boxo/ipld/merkledag"
6 "github.com/ipfs/boxo/path"
12 - cid "github.com/ipfs/go-cid"
13 - cidutil "github.com/ipfs/go-cidutil"
7 coreiface "github.com/ipfs/kubo/core/coreiface"
8 caopts "github.com/ipfs/kubo/core/coreiface/options"
16 - "github.com/ipfs/kubo/tracing"
9 peer "github.com/libp2p/go-libp2p/core/peer"
18 - routing "github.com/libp2p/go-libp2p/core/routing"
19 - "go.opentelemetry.io/otel/attribute"
20 - "go.opentelemetry.io/otel/trace"
10 )
11
12 type DhtAPI CoreAPI
13
14 +// nolint deprecated
15 +// Deprecated: use [RoutingAPI.FindPeer] instead.
16 func (api *DhtAPI) FindPeer(ctx context.Context, p peer.ID) (peer.AddrInfo, error) {
26 - ctx, span := tracing.Span(ctx, "CoreAPI.DhtAPI", "FindPeer", trace.WithAttributes(attribute.String("peer", p.String())))
27 - defer span.End()
28 - err := api.checkOnline(false)
29 - if err != nil {
30 - return peer.AddrInfo{}, err
31 - }
32 -
33 - pi, err := api.routing.FindPeer(ctx, peer.ID(p))
34 - if err != nil {
35 - return peer.AddrInfo{}, err
36 - }
37 -
38 - return pi, nil
17 + return api.core().Routing().FindPeer(ctx, p)
18 }
19
20 +// nolint deprecated
21 +// Deprecated: use [RoutingAPI.FindProviders] instead.
22 func (api *DhtAPI) FindProviders(ctx context.Context, p path.Path, opts ...caopts.DhtFindProvidersOption) (<-chan peer.AddrInfo, error) {
42 - ctx, span := tracing.Span(ctx, "CoreAPI.DhtAPI", "FindProviders", trace.WithAttributes(attribute.String("path", p.String())))
43 - defer span.End()
44 -
45 - settings, err := caopts.DhtFindProvidersOptions(opts...)
46 - if err != nil {
47 - return nil, err
48 - }
49 - span.SetAttributes(attribute.Int("numproviders", settings.NumProviders))
50 -
51 - err = api.checkOnline(false)
52 - if err != nil {
53 - return nil, err
54 - }
55 -
56 - rp, _, err := api.core().ResolvePath(ctx, p)
57 - if err != nil {
58 - return nil, err
59 - }
60 -
61 - numProviders := settings.NumProviders
62 - if numProviders < 1 {
63 - return nil, fmt.Errorf("number of providers must be greater than 0")
64 - }
65 -
66 - pchan := api.routing.FindProvidersAsync(ctx, rp.RootCid(), numProviders)
67 - return pchan, nil
23 + return api.core().Routing().FindProviders(ctx, p, opts...)
24 }
25
70 -func (api *DhtAPI) Provide(ctx context.Context, path path.Path, opts ...caopts.DhtProvideOption) error {
71 - ctx, span := tracing.Span(ctx, "CoreAPI.DhtAPI", "Provide", trace.WithAttributes(attribute.String("path", path.String())))
72 - defer span.End()
73 -
74 - settings, err := caopts.DhtProvideOptions(opts...)
75 - if err != nil {
76 - return err
77 - }
78 - span.SetAttributes(attribute.Bool("recursive", settings.Recursive))
79 -
80 - err = api.checkOnline(false)
81 - if err != nil {
82 - return err
83 - }
84 -
85 - rp, _, err := api.core().ResolvePath(ctx, path)
86 - if err != nil {
87 - return err
88 - }
89 -
90 - c := rp.RootCid()
91 -
92 - has, err := api.blockstore.Has(ctx, c)
93 - if err != nil {
94 - return err
95 - }
96 -
97 - if !has {
98 - return fmt.Errorf("block %s not found locally, cannot provide", c)
99 - }
100 -
101 - if settings.Recursive {
102 - err = provideKeysRec(ctx, api.routing, api.blockstore, []cid.Cid{c})
103 - } else {
104 - err = provideKeys(ctx, api.routing, []cid.Cid{c})
105 - }
106 - if err != nil {
107 - return err
108 - }
109 -
110 - return nil
111 -}
112 -
113 -func provideKeys(ctx context.Context, r routing.Routing, cids []cid.Cid) error {
114 - for _, c := range cids {
115 - err := r.Provide(ctx, c, true)
116 - if err != nil {
117 - return err
118 - }
119 - }
120 - return nil
121 -}
122 -
123 -func provideKeysRec(ctx context.Context, r routing.Routing, bs blockstore.Blockstore, cids []cid.Cid) error {
124 - provided := cidutil.NewStreamingSet()
125 -
126 - errCh := make(chan error)
127 - go func() {
128 - dserv := dag.NewDAGService(blockservice.New(bs, offline.Exchange(bs)))
129 - for _, c := range cids {
130 - err := dag.Walk(ctx, dag.GetLinksDirect(dserv), c, provided.Visitor(ctx))
131 - if err != nil {
132 - errCh <- err
133 - }
134 - }
135 - }()
136 -
137 - for {
138 - select {
139 - case k := <-provided.New:
140 - err := r.Provide(ctx, k, true)
141 - if err != nil {
142 - return err
143 - }
144 - case err := <-errCh:
145 - return err
146 - case <-ctx.Done():
147 - return ctx.Err()
148 - }
149 - }
26 +// nolint deprecated
27 +// Deprecated: use [RoutingAPI.Provide] instead.
28 +func (api *DhtAPI) Provide(ctx context.Context, p path.Path, opts ...caopts.DhtProvideOption) error {
29 + return api.core().Routing().Provide(ctx, p, opts...)
30 }
31
32 func (api *DhtAPI) core() coreiface.CoreAPI {
core/coreapi/routing.go
+149 -6
@@ -3,17 +3,29 @@ package coreapi
3 import (
4 "context"
5 "errors"
6 + "fmt"
7 "strings"
8
9 + blockservice "github.com/ipfs/boxo/blockservice"
10 + blockstore "github.com/ipfs/boxo/blockstore"
11 + offline "github.com/ipfs/boxo/exchange/offline"
12 + dag "github.com/ipfs/boxo/ipld/merkledag"
13 + "github.com/ipfs/boxo/path"
14 + cid "github.com/ipfs/go-cid"
15 + cidutil "github.com/ipfs/go-cidutil"
16 coreiface "github.com/ipfs/kubo/core/coreiface"
17 caopts "github.com/ipfs/kubo/core/coreiface/options"
18 + "github.com/ipfs/kubo/tracing"
19 peer "github.com/libp2p/go-libp2p/core/peer"
20 + routing "github.com/libp2p/go-libp2p/core/routing"
21 + "go.opentelemetry.io/otel/attribute"
22 + "go.opentelemetry.io/otel/trace"
23 )
24
25 type RoutingAPI CoreAPI
26
15 -func (r *RoutingAPI) Get(ctx context.Context, key string) ([]byte, error) {
16 - if !r.nd.IsOnline {
27 +func (api *RoutingAPI) Get(ctx context.Context, key string) ([]byte, error) {
28 + if !api.nd.IsOnline {
29 return nil, coreiface.ErrOffline
30 }
31
@@ -22,16 +34,16 @@ func (r *RoutingAPI) Get(ctx context.Context, key string) ([]byte, error) {
34 return nil, err
35 }
36
25 - return r.routing.GetValue(ctx, dhtKey)
37 + return api.routing.GetValue(ctx, dhtKey)
38 }
39
28 -func (r *RoutingAPI) Put(ctx context.Context, key string, value []byte, opts ...caopts.RoutingPutOption) error {
40 +func (api *RoutingAPI) Put(ctx context.Context, key string, value []byte, opts ...caopts.RoutingPutOption) error {
41 options, err := caopts.RoutingPutOptions(opts...)
42 if err != nil {
43 return err
44 }
45
34 - err = r.checkOnline(options.AllowOffline)
46 + err = api.checkOnline(options.AllowOffline)
47 if err != nil {
48 return err
49 }
@@ -41,7 +53,7 @@ func (r *RoutingAPI) Put(ctx context.Context, key string, value []byte, opts ...
53 return err
54 }
55
44 - return r.routing.PutValue(ctx, dhtKey, value)
56 + return api.routing.PutValue(ctx, dhtKey, value)
57 }
58
59 func normalizeKey(s string) (string, error) {
@@ -58,3 +70,134 @@ func normalizeKey(s string) (string, error) {
70 }
71 return strings.Join(append(parts[:2], string(k)), "/"), nil
72 }
73 +
74 +func (api *RoutingAPI) FindPeer(ctx context.Context, p peer.ID) (peer.AddrInfo, error) {
75 + ctx, span := tracing.Span(ctx, "CoreAPI.DhtAPI", "FindPeer", trace.WithAttributes(attribute.String("peer", p.String())))
76 + defer span.End()
77 + err := api.checkOnline(false)
78 + if err != nil {
79 + return peer.AddrInfo{}, err
80 + }
81 +
82 + pi, err := api.routing.FindPeer(ctx, peer.ID(p))
83 + if err != nil {
84 + return peer.AddrInfo{}, err
85 + }
86 +
87 + return pi, nil
88 +}
89 +
90 +func (api *RoutingAPI) FindProviders(ctx context.Context, p path.Path, opts ...caopts.RoutingFindProvidersOption) (<-chan peer.AddrInfo, error) {
91 + ctx, span := tracing.Span(ctx, "CoreAPI.DhtAPI", "FindProviders", trace.WithAttributes(attribute.String("path", p.String())))
92 + defer span.End()
93 +
94 + settings, err := caopts.RoutingFindProvidersOptions(opts...)
95 + if err != nil {
96 + return nil, err
97 + }
98 + span.SetAttributes(attribute.Int("numproviders", settings.NumProviders))
99 +
100 + err = api.checkOnline(false)
101 + if err != nil {
102 + return nil, err
103 + }
104 +
105 + rp, _, err := api.core().ResolvePath(ctx, p)
106 + if err != nil {
107 + return nil, err
108 + }
109 +
110 + numProviders := settings.NumProviders
111 + if numProviders < 1 {
112 + return nil, fmt.Errorf("number of providers must be greater than 0")
113 + }
114 +
115 + pchan := api.routing.FindProvidersAsync(ctx, rp.RootCid(), numProviders)
116 + return pchan, nil
117 +}
118 +
119 +func (api *RoutingAPI) Provide(ctx context.Context, path path.Path, opts ...caopts.RoutingProvideOption) error {
120 + ctx, span := tracing.Span(ctx, "CoreAPI.DhtAPI", "Provide", trace.WithAttributes(attribute.String("path", path.String())))
121 + defer span.End()
122 +
123 + settings, err := caopts.RoutingProvideOptions(opts...)
124 + if err != nil {
125 + return err
126 + }
127 + span.SetAttributes(attribute.Bool("recursive", settings.Recursive))
128 +
129 + err = api.checkOnline(false)
130 + if err != nil {
131 + return err
132 + }
133 +
134 + rp, _, err := api.core().ResolvePath(ctx, path)
135 + if err != nil {
136 + return err
137 + }
138 +
139 + c := rp.RootCid()
140 +
141 + has, err := api.blockstore.Has(ctx, c)
142 + if err != nil {
143 + return err
144 + }
145 +
146 + if !has {
147 + return fmt.Errorf("block %s not found locally, cannot provide", c)
148 + }
149 +
150 + if settings.Recursive {
151 + err = provideKeysRec(ctx, api.routing, api.blockstore, []cid.Cid{c})
152 + } else {
153 + err = provideKeys(ctx, api.routing, []cid.Cid{c})
154 + }
155 + if err != nil {
156 + return err
157 + }
158 +
159 + return nil
160 +}
161 +
162 +func provideKeys(ctx context.Context, r routing.Routing, cids []cid.Cid) error {
163 + for _, c := range cids {
164 + err := r.Provide(ctx, c, true)
165 + if err != nil {
166 + return err
167 + }
168 + }
169 + return nil
170 +}
171 +
172 +func provideKeysRec(ctx context.Context, r routing.Routing, bs blockstore.Blockstore, cids []cid.Cid) error {
173 + provided := cidutil.NewStreamingSet()
174 +
175 + errCh := make(chan error)
176 + go func() {
177 + dserv := dag.NewDAGService(blockservice.New(bs, offline.Exchange(bs)))
178 + for _, c := range cids {
179 + err := dag.Walk(ctx, dag.GetLinksDirect(dserv), c, provided.Visitor(ctx))
180 + if err != nil {
181 + errCh <- err
182 + }
183 + }
184 + }()
185 +
186 + for {
187 + select {
188 + case k := <-provided.New:
189 + err := r.Provide(ctx, k, true)
190 + if err != nil {
191 + return err
192 + }
193 + case err := <-errCh:
194 + return err
195 + case <-ctx.Done():
196 + return ctx.Err()
197 + }
198 + }
199 +}
200 +
201 +func (api *RoutingAPI) core() coreiface.CoreAPI {
202 + return (*CoreAPI)(api)
203 +}
core/coreiface/coreapi.go
+2 -1
@@ -34,7 +34,8 @@ type CoreAPI interface {
34 // Object returns an implementation of Object API
35 Object() ObjectAPI
36
37 - // Dht returns an implementation of Dht API
37 + // nolint deprecated
38 + // Deprecated: use [Routing] instead.
39 Dht() DhtAPI
40
41 // Swarm returns an implementation of Swarm API
core/coreiface/dht.go
+8 -10
@@ -4,24 +4,22 @@ import (
4 "context"
5
6 "github.com/ipfs/boxo/path"
7 -
7 "github.com/ipfs/kubo/core/coreiface/options"
9 -
8 "github.com/libp2p/go-libp2p/core/peer"
9 )
10
13 -// DhtAPI specifies the interface to the DHT
14 -// Note: This API will likely get deprecated in near future, see
15 -// https://github.com/ipfs/interface-ipfs-core/issues/249 for more context.
11 +// nolint deprecated
12 +// Deprecated: use [RoutingAPI] instead.
13 type DhtAPI interface {
17 - // FindPeer queries the DHT for all of the multiaddresses associated with a
18 - // Peer ID
14 + // nolint deprecated
15 + // Deprecated: use [RoutingAPI.FindPeer] instead.
16 FindPeer(context.Context, peer.ID) (peer.AddrInfo, error)
17
21 - // FindProviders finds peers in the DHT who can provide a specific value
22 - // given a key.
18 + // nolint deprecated
19 + // Deprecated: use [RoutingAPI.FindProviders] instead.
20 FindProviders(context.Context, path.Path, ...options.DhtFindProvidersOption) (<-chan peer.AddrInfo, error)
21
25 - // Provide announces to the network that you are providing given values
22 + // nolint deprecated
23 + // Deprecated: use [RoutingAPI.Provide] instead.
24 Provide(context.Context, path.Path, ...options.DhtProvideOption) error
25 }
core/coreiface/options/dht.go
+21 -56
@@ -1,64 +1,29 @@
1 package options
2
3 -type DhtProvideSettings struct {
4 - Recursive bool
5 -}
3 +// nolint deprecated
4 +// Deprecated: use [RoutingProvideSettings] instead.
5 +type DhtProvideSettings = RoutingProvideSettings
6
7 -type DhtFindProvidersSettings struct {
8 - NumProviders int
9 -}
7 +// nolint deprecated
8 +// Deprecated: use [RoutingFindProvidersSettings] instead.
9 +type DhtFindProvidersSettings = RoutingFindProvidersSettings
10
11 -type (
12 - DhtProvideOption func(*DhtProvideSettings) error
13 - DhtFindProvidersOption func(*DhtFindProvidersSettings) error
14 -)
11 +// nolint deprecated
12 +// Deprecated: use [RoutingProvideOption] instead.
13 +type DhtProvideOption = RoutingProvideOption
14
16 -func DhtProvideOptions(opts ...DhtProvideOption) (*DhtProvideSettings, error) {
17 - options := &DhtProvideSettings{
18 - Recursive: false,
19 - }
15 +// nolint deprecated
16 +// Deprecated: use [RoutingFindProvidersOption] instead.
17 +type DhtFindProvidersOption = RoutingFindProvidersOption
18
21 - for _, opt := range opts {
22 - err := opt(options)
23 - if err != nil {
24 - return nil, err
25 - }
26 - }
27 - return options, nil
28 -}
19 +// nolint deprecated
20 +// Deprecated: use [RoutingProvideOptions] instead.
21 +var DhtProvideOptions = RoutingProvideOptions
22
30 -func DhtFindProvidersOptions(opts ...DhtFindProvidersOption) (*DhtFindProvidersSettings, error) {
31 - options := &DhtFindProvidersSettings{
32 - NumProviders: 20,
33 - }
23 +// nolint deprecated
24 +// Deprecated: use [RoutingFindProvidersOptions] instead.
25 +var DhtFindProvidersOptions = RoutingFindProvidersOptions
26
35 - for _, opt := range opts {
36 - err := opt(options)
37 - if err != nil {
38 - return nil, err
39 - }
40 - }
41 - return options, nil
42 -}
43 -
44 -type dhtOpts struct{}
45 -
46 -var Dht dhtOpts
47 -
48 -// Recursive is an option for Dht.Provide which specifies whether to provide
49 -// the given path recursively
50 -func (dhtOpts) Recursive(recursive bool) DhtProvideOption {
51 - return func(settings *DhtProvideSettings) error {
52 - settings.Recursive = recursive
53 - return nil
54 - }
55 -}
56 -
57 -// NumProviders is an option for Dht.FindProviders which specifies the
58 -// number of peers to look for. Default is 20
59 -func (dhtOpts) NumProviders(numProviders int) DhtFindProvidersOption {
60 - return func(settings *DhtFindProvidersSettings) error {
61 - settings.NumProviders = numProviders
62 - return nil
63 - }
64 -}
27 +// nolint deprecated
28 +// Deprecated: use [Routing] instead.
29 +var Dht = Routing
core/coreiface/options/routing.go
+67 -4
@@ -21,13 +21,76 @@ func RoutingPutOptions(opts ...RoutingPutOption) (*RoutingPutSettings, error) {
21 return options, nil
22 }
23
24 -type putOpts struct{}
24 +// nolint deprecated
25 +// Deprecated: use [Routing] instead.
26 +var Put = Routing
27
26 -var Put putOpts
28 +type RoutingProvideSettings struct {
29 + Recursive bool
30 +}
31 +
32 +type RoutingFindProvidersSettings struct {
33 + NumProviders int
34 +}
35 +
36 +type (
37 + RoutingProvideOption func(*DhtProvideSettings) error
38 + RoutingFindProvidersOption func(*DhtFindProvidersSettings) error
39 +)
40 +
41 +func RoutingProvideOptions(opts ...RoutingProvideOption) (*RoutingProvideSettings, error) {
42 + options := &RoutingProvideSettings{
43 + Recursive: false,
44 + }
45 +
46 + for _, opt := range opts {
47 + err := opt(options)
48 + if err != nil {
49 + return nil, err
50 + }
51 + }
52 + return options, nil
53 +}
54 +
55 +func RoutingFindProvidersOptions(opts ...RoutingFindProvidersOption) (*RoutingFindProvidersSettings, error) {
56 + options := &RoutingFindProvidersSettings{
57 + NumProviders: 20,
58 + }
59 +
60 + for _, opt := range opts {
61 + err := opt(options)
62 + if err != nil {
63 + return nil, err
64 + }
65 + }
66 + return options, nil
67 +}
68 +
69 +type routingOpts struct{}
70 +
71 +var Routing routingOpts
72 +
73 +// Recursive is an option for [Routing.Provide] which specifies whether to provide
74 +// the given path recursively.
75 +func (routingOpts) Recursive(recursive bool) RoutingProvideOption {
76 + return func(settings *DhtProvideSettings) error {
77 + settings.Recursive = recursive
78 + return nil
79 + }
80 +}
81 +
82 +// NumProviders is an option for [Routing.FindProviders] which specifies the
83 +// number of peers to look for. Default is 20.
84 +func (routingOpts) NumProviders(numProviders int) RoutingFindProvidersOption {
85 + return func(settings *DhtFindProvidersSettings) error {
86 + settings.NumProviders = numProviders
87 + return nil
88 + }
89 +}
90
28 -// AllowOffline is an option for Routing.Put which specifies whether to allow
91 +// AllowOffline is an option for [Routing.Put] which specifies whether to allow
92 // publishing when the node is offline. Default value is false
30 -func (putOpts) AllowOffline(allow bool) RoutingPutOption {
93 +func (routingOpts) AllowOffline(allow bool) RoutingPutOption {
94 return func(settings *RoutingPutSettings) error {
95 settings.AllowOffline = allow
96 return nil
core/coreiface/routing.go
+13
@@ -3,7 +3,9 @@ package iface
3 import (
4 "context"
5
6 + "github.com/ipfs/boxo/path"
7 "github.com/ipfs/kubo/core/coreiface/options"
8 + "github.com/libp2p/go-libp2p/core/peer"
9 )
10
11 // RoutingAPI specifies the interface to the routing layer.
@@ -13,4 +15,15 @@ type RoutingAPI interface {
15
16 // Put sets a value for a given key
17 Put(ctx context.Context, key string, value []byte, opts ...options.RoutingPutOption) error
18 +
19 + // FindPeer queries the routing system for all the multiaddresses associated
20 + // with the given [peer.ID].
21 + FindPeer(context.Context, peer.ID) (peer.AddrInfo, error)
22 +
23 + // FindProviders finds the peers in the routing system who can provide a specific
24 + // value given a key.
25 + FindProviders(context.Context, path.Path, ...options.RoutingFindProvidersOption) (<-chan peer.AddrInfo, error)
26 +
27 + // Provide announces to the network that you are providing given values
28 + Provide(context.Context, path.Path, ...options.RoutingProvideOption) error
29 }
core/coreiface/tests/api.go
-1
@@ -75,7 +75,6 @@ func TestApi(p Provider) func(t *testing.T) {
75 return func(t *testing.T) {
76 t.Run("Block", tp.TestBlock)
77 t.Run("Dag", tp.TestDag)
78 - t.Run("Dht", tp.TestDht)
78 t.Run("Key", tp.TestKey)
79 t.Run("Name", tp.TestName)
80 t.Run("Object", tp.TestObject)
core/coreiface/tests/dht.go deleted
-166
@@ -1,166 +0,0 @@
1 -package tests
2 -
3 -import (
4 - "context"
5 - "io"
6 - "testing"
7 - "time"
8 -
9 - iface "github.com/ipfs/kubo/core/coreiface"
10 - "github.com/ipfs/kubo/core/coreiface/options"
11 -)
12 -
13 -func (tp *TestSuite) TestDht(t *testing.T) {
14 - tp.hasApi(t, func(api iface.CoreAPI) error {
15 - if api.Dht() == nil {
16 - return errAPINotImplemented
17 - }
18 - return nil
19 - })
20 -
21 - t.Run("TestDhtFindPeer", tp.TestDhtFindPeer)
22 - t.Run("TestDhtFindProviders", tp.TestDhtFindProviders)
23 - t.Run("TestDhtProvide", tp.TestDhtProvide)
24 -}
25 -
26 -func (tp *TestSuite) TestDhtFindPeer(t *testing.T) {
27 - ctx, cancel := context.WithCancel(context.Background())
28 - defer cancel()
29 - apis, err := tp.MakeAPISwarm(t, ctx, 5)
30 - if err != nil {
31 - t.Fatal(err)
32 - }
33 -
34 - self0, err := apis[0].Key().Self(ctx)
35 - if err != nil {
36 - t.Fatal(err)
37 - }
38 -
39 - laddrs0, err := apis[0].Swarm().LocalAddrs(ctx)
40 - if err != nil {
41 - t.Fatal(err)
42 - }
43 - if len(laddrs0) != 1 {
44 - t.Fatal("unexpected number of local addrs")
45 - }
46 -
47 - time.Sleep(3 * time.Second)
48 -
49 - pi, err := apis[2].Dht().FindPeer(ctx, self0.ID())
50 - if err != nil {
51 - t.Fatal(err)
52 - }
53 -
54 - if pi.Addrs[0].String() != laddrs0[0].String() {
55 - t.Errorf("got unexpected address from FindPeer: %s", pi.Addrs[0].String())
56 - }
57 -
58 - self2, err := apis[2].Key().Self(ctx)
59 - if err != nil {
60 - t.Fatal(err)
61 - }
62 -
63 - pi, err = apis[1].Dht().FindPeer(ctx, self2.ID())
64 - if err != nil {
65 - t.Fatal(err)
66 - }
67 -
68 - laddrs2, err := apis[2].Swarm().LocalAddrs(ctx)
69 - if err != nil {
70 - t.Fatal(err)
71 - }
72 - if len(laddrs2) != 1 {
73 - t.Fatal("unexpected number of local addrs")
74 - }
75 -
76 - if pi.Addrs[0].String() != laddrs2[0].String() {
77 - t.Errorf("got unexpected address from FindPeer: %s", pi.Addrs[0].String())
78 - }
79 -}
80 -
81 -func (tp *TestSuite) TestDhtFindProviders(t *testing.T) {
82 - ctx, cancel := context.WithCancel(context.Background())
83 - defer cancel()
84 - apis, err := tp.MakeAPISwarm(t, ctx, 5)
85 - if err != nil {
86 - t.Fatal(err)
87 - }
88 -
89 - p, err := addTestObject(ctx, apis[0])
90 - if err != nil {
91 - t.Fatal(err)
92 - }
93 -
94 - time.Sleep(3 * time.Second)
95 -
96 - out, err := apis[2].Dht().FindProviders(ctx, p, options.Dht.NumProviders(1))
97 - if err != nil {
98 - t.Fatal(err)
99 - }
100 -
101 - provider := <-out
102 -
103 - self0, err := apis[0].Key().Self(ctx)
104 - if err != nil {
105 - t.Fatal(err)
106 - }
107 -
108 - if provider.ID.String() != self0.ID().String() {
109 - t.Errorf("got wrong provider: %s != %s", provider.ID.String(), self0.ID().String())
110 - }
111 -}
112 -
113 -func (tp *TestSuite) TestDhtProvide(t *testing.T) {
114 - ctx, cancel := context.WithCancel(context.Background())
115 - defer cancel()
116 - apis, err := tp.MakeAPISwarm(t, ctx, 5)
117 - if err != nil {
118 - t.Fatal(err)
119 - }
120 -
121 - off0, err := apis[0].WithOptions(options.Api.Offline(true))
122 - if err != nil {
123 - t.Fatal(err)
124 - }
125 -
126 - s, err := off0.Block().Put(ctx, &io.LimitedReader{R: rnd, N: 4092})
127 - if err != nil {
128 - t.Fatal(err)
129 - }
130 -
131 - p := s.Path()
132 -
133 - time.Sleep(3 * time.Second)
134 -
135 - out, err := apis[2].Dht().FindProviders(ctx, p, options.Dht.NumProviders(1))
136 - if err != nil {
137 - t.Fatal(err)
138 - }
139 -
140 - _, ok := <-out
141 -
142 - if ok {
143 - t.Fatal("did not expect to find any providers")
144 - }
145 -
146 - self0, err := apis[0].Key().Self(ctx)
147 - if err != nil {
148 - t.Fatal(err)
149 - }
150 -
151 - err = apis[0].Dht().Provide(ctx, p)
152 - if err != nil {
153 - t.Fatal(err)
154 - }
155 -
156 - out, err = apis[2].Dht().FindProviders(ctx, p, options.Dht.NumProviders(1))
157 - if err != nil {
158 - t.Fatal(err)
159 - }
160 -
161 - provider := <-out
162 -
163 - if provider.ID.String() != self0.ID().String() {
164 - t.Errorf("got wrong provider: %s != %s", provider.ID.String(), self0.ID().String())
165 - }
166 -}
core/coreiface/tests/routing.go
+147 -1
@@ -2,6 +2,7 @@ package tests
2
3 import (
4 "context"
5 + "io"
6 "testing"
7 "time"
8
@@ -23,6 +24,9 @@ func (tp *TestSuite) TestRouting(t *testing.T) {
24 t.Run("TestRoutingGet", tp.TestRoutingGet)
25 t.Run("TestRoutingPut", tp.TestRoutingPut)
26 t.Run("TestRoutingPutOffline", tp.TestRoutingPutOffline)
27 + t.Run("TestRoutingFindPeer", tp.TestRoutingFindPeer)
28 + t.Run("TestRoutingFindProviders", tp.TestRoutingFindProviders)
29 + t.Run("TestRoutingProvide", tp.TestRoutingProvide)
30 }
31
32 func (tp *TestSuite) testRoutingPublishKey(t *testing.T, ctx context.Context, api iface.CoreAPI, opts ...options.NamePublishOption) (path.Path, ipns.Name) {
@@ -95,6 +99,148 @@ func (tp *TestSuite) TestRoutingPutOffline(t *testing.T) {
99 err = api.Routing().Put(ctx, ipns.NamespacePrefix+name.String(), data)
100 require.Error(t, err, "this operation should fail because we are offline")
101
98 - err = api.Routing().Put(ctx, ipns.NamespacePrefix+name.String(), data, options.Put.AllowOffline(true))
102 + err = api.Routing().Put(ctx, ipns.NamespacePrefix+name.String(), data, options.Routing.AllowOffline(true))
103 require.NoError(t, err)
104 }
105 +
106 +func (tp *TestSuite) TestRoutingFindPeer(t *testing.T) {
107 + ctx, cancel := context.WithCancel(context.Background())
108 + defer cancel()
109 + apis, err := tp.MakeAPISwarm(t, ctx, 5)
110 + if err != nil {
111 + t.Fatal(err)
112 + }
113 +
114 + self0, err := apis[0].Key().Self(ctx)
115 + if err != nil {
116 + t.Fatal(err)
117 + }
118 +
119 + laddrs0, err := apis[0].Swarm().LocalAddrs(ctx)
120 + if err != nil {
121 + t.Fatal(err)
122 + }
123 + if len(laddrs0) != 1 {
124 + t.Fatal("unexpected number of local addrs")
125 + }
126 +
127 + time.Sleep(3 * time.Second)
128 +
129 + pi, err := apis[2].Routing().FindPeer(ctx, self0.ID())
130 + if err != nil {
131 + t.Fatal(err)
132 + }
133 +
134 + if pi.Addrs[0].String() != laddrs0[0].String() {
135 + t.Errorf("got unexpected address from FindPeer: %s", pi.Addrs[0].String())
136 + }
137 +
138 + self2, err := apis[2].Key().Self(ctx)
139 + if err != nil {
140 + t.Fatal(err)
141 + }
142 +
143 + pi, err = apis[1].Routing().FindPeer(ctx, self2.ID())
144 + if err != nil {
145 + t.Fatal(err)
146 + }
147 +
148 + laddrs2, err := apis[2].Swarm().LocalAddrs(ctx)
149 + if err != nil {
150 + t.Fatal(err)
151 + }
152 + if len(laddrs2) != 1 {
153 + t.Fatal("unexpected number of local addrs")
154 + }
155 +
156 + if pi.Addrs[0].String() != laddrs2[0].String() {
157 + t.Errorf("got unexpected address from FindPeer: %s", pi.Addrs[0].String())
158 + }
159 +}
160 +
161 +func (tp *TestSuite) TestRoutingFindProviders(t *testing.T) {
162 + ctx, cancel := context.WithCancel(context.Background())
163 + defer cancel()
164 + apis, err := tp.MakeAPISwarm(t, ctx, 5)
165 + if err != nil {
166 + t.Fatal(err)
167 + }
168 +
169 + p, err := addTestObject(ctx, apis[0])
170 + if err != nil {
171 + t.Fatal(err)
172 + }
173 +
174 + time.Sleep(3 * time.Second)
175 +
176 + out, err := apis[2].Routing().FindProviders(ctx, p, options.Routing.NumProviders(1))
177 + if err != nil {
178 + t.Fatal(err)
179 + }
180 +
181 + provider := <-out
182 +
183 + self0, err := apis[0].Key().Self(ctx)
184 + if err != nil {
185 + t.Fatal(err)
186 + }
187 +
188 + if provider.ID.String() != self0.ID().String() {
189 + t.Errorf("got wrong provider: %s != %s", provider.ID.String(), self0.ID().String())
190 + }
191 +}
192 +
193 +func (tp *TestSuite) TestRoutingProvide(t *testing.T) {
194 + ctx, cancel := context.WithCancel(context.Background())
195 + defer cancel()
196 + apis, err := tp.MakeAPISwarm(t, ctx, 5)
197 + if err != nil {
198 + t.Fatal(err)
199 + }
200 +
201 + off0, err := apis[0].WithOptions(options.Api.Offline(true))
202 + if err != nil {
203 + t.Fatal(err)
204 + }
205 +
206 + s, err := off0.Block().Put(ctx, &io.LimitedReader{R: rnd, N: 4092})
207 + if err != nil {
208 + t.Fatal(err)
209 + }
210 +
211 + p := s.Path()
212 +
213 + time.Sleep(3 * time.Second)
214 +
215 + out, err := apis[2].Routing().FindProviders(ctx, p, options.Routing.NumProviders(1))
216 + if err != nil {
217 + t.Fatal(err)
218 + }
219 +
220 + _, ok := <-out
221 +
222 + if ok {
223 + t.Fatal("did not expect to find any providers")
224 + }
225 +
226 + self0, err := apis[0].Key().Self(ctx)
227 + if err != nil {
228 + t.Fatal(err)
229 + }
230 +
231 + err = apis[0].Routing().Provide(ctx, p)
232 + if err != nil {
233 + t.Fatal(err)
234 + }
235 +
236 + out, err = apis[2].Routing().FindProviders(ctx, p, options.Routing.NumProviders(1))
237 + if err != nil {
238 + t.Fatal(err)
239 + }
240 +
241 + provider := <-out
242 +
243 + if provider.ID.String() != self0.ID().String() {
244 + t.Errorf("got wrong provider: %s != %s", provider.ID.String(), self0.ID().String())
245 + }
246 +}
docs/changelogs/v0.27.md
+8
@@ -7,6 +7,8 @@
7 - [Overview](#overview)
8 - [🔦 Highlights](#-highlights)
9 - [Gateway: support for `/api/v0` is deprecated](#gateway-support-for-apiv0-is-deprecated)
10 + - [IPNS resolver cache's TTL can now be configured](#ipns-resolver-caches-ttl-can-now-be-configured)
11 + - [RPC client: deprecated DHT API, added Routing API](#rpc-client-deprecated-dht-api-added-routing-api)
12 - [📝 Changelog](#-changelog)
13 - [👨‍👩‍👧‍👦 Contributors](#-contributors)
14
@@ -24,6 +26,12 @@ If you have a legacy software that relies on this behavior, and want to expose p
26
27 You can now configure the upper-bound of a cached IPNS entry's Time-To-Live via [`Ipns.MaxCacheTTL`](https://github.com/ipfs/kubo/blob/master/docs/config.md#ipnsmaxcachettl).
28
29 +#### RPC client: deprecated DHT API, added Routing API
30 +
31 +The RPC client now includes a Routing API to match the available commands in `/api/v0/routing`. In addition, the DHT API has been marked as deprecated.
32 +
33 +In the next version, all DHT deprecated methods will be removed from the Go RPC client.
34 +
35 ### 📝 Changelog
36
37 ### 👨‍👩‍👧‍👦 Contributors
docs/file-transfer.md
+2 -2
@@ -68,12 +68,12 @@ pitfalls that people run into)
68 ### Checking providers
69 When requesting content on ipfs, nodes search the DHT for 'provider records' to
70 see who has what content. Let's manually do that on node B to make sure that
71 -node B is able to determine that node A has the data. Run `ipfs dht findprovs
71 +node B is able to determine that node A has the data. Run `ipfs routing findprovs
72 <hash>`. We expect to see the peer ID of node A printed out. If this command
73 returns nothing (or returns IDs that are not node A), then no record of A
74 having the data exists on the network. This can happen if the data is added
75 while node A does not have a daemon running. If this happens, you can run `ipfs
76 -dht provide <hash>` on node A to announce to the network that you have that
76 +routing provide <hash>` on node A to announce to the network that you have that
77 hash. Then if you restart the `ipfs get` command, node B should now be able
78 to tell that node A has the content it wants. If node A's peer ID showed up in
79 the initial `findprovs` call, or manually providing the hash didn't resolve the
test/cli/dht_opt_prov_test.go
+1 -1
@@ -22,7 +22,7 @@ func TestDHTOptimisticProvide(t *testing.T) {
22 nodes.StartDaemons().Connect()
23
24 hash := nodes[0].IPFSAddStr(testutils.RandomStr(100))
25 - nodes[0].IPFS("dht", "provide", hash)
25 + nodes[0].IPFS("routing", "provide", hash)
26
27 res := nodes[1].IPFS("routing", "findprovs", "--num-providers=1", hash)
28 assert.Equal(t, nodes[0].PeerID().String(), res.Stdout.Trimmed())
test/sharness/lib/test-lib.sh
+2 -2
@@ -512,7 +512,7 @@ port_from_maddr() {
512
513 findprovs_empty() {
514 test_expect_success 'findprovs '$1' succeeds' '
515 - ipfsi 1 dht findprovs -n 1 '$1' > findprovsOut
515 + ipfsi 1 routing findprovs -n 1 '$1' > findprovsOut
516 '
517
518 test_expect_success "findprovs $1 output is empty" '
@@ -522,7 +522,7 @@ findprovs_empty() {
522
523 findprovs_expect() {
524 test_expect_success 'findprovs '$1' succeeds' '
525 - ipfsi 1 dht findprovs -n 1 '$1' > findprovsOut &&
525 + ipfsi 1 routing findprovs -n 1 '$1' > findprovsOut &&
526 echo '$2' > expected
527 '
528