@cryptotaxi247 / kubo / commits / 1b154e245

feat(routing): allow-offline with routing put (#278)

This commit was moved from ipfs/boxo@8059f183d86648f69ad562546b4797bc148c0984

Laurent Senta committed May 3, 2023 at 12:59 UTC 1b154e24568ab4970740bc49e9364c748dc05738
7 files changed +109 -24
core/coreiface/options/routing.go new
+35
@@ -0,0 +1,35 @@
1 +package options
2 +
3 +type RoutingPutSettings struct {
4 + AllowOffline bool
5 +}
6 +
7 +type RoutingPutOption func(*RoutingPutSettings) error
8 +
9 +func RoutingPutOptions(opts ...RoutingPutOption) (*RoutingPutSettings, error) {
10 + options := &RoutingPutSettings{
11 + AllowOffline: false,
12 + }
13 +
14 + for _, opt := range opts {
15 + err := opt(options)
16 + if err != nil {
17 + return nil, err
18 + }
19 + }
20 +
21 + return options, nil
22 +}
23 +
24 +type putOpts struct{}
25 +
26 +var Put putOpts
27 +
28 +// AllowOffline is an option for Routing.Put which specifies whether to allow
29 +// publishing when the node is offline. Default value is false
30 +func (putOpts) AllowOffline(allow bool) RoutingPutOption {
31 + return func(settings *RoutingPutSettings) error {
32 + settings.AllowOffline = allow
33 + return nil
34 + }
35 +}
core/coreiface/routing.go
+3 -1
@@ -2,6 +2,8 @@ package iface
2
3 import (
4 "context"
5 +
6 + "github.com/ipfs/boxo/coreiface/options"
7 )
8
9 // RoutingAPI specifies the interface to the routing layer.
@@ -10,5 +12,5 @@ type RoutingAPI interface {
12 Get(context.Context, string) ([]byte, error)
13
14 // Put sets a value for a given key
13 - Put(ctx context.Context, key string, value []byte) error
15 + Put(ctx context.Context, key string, value []byte, opts ...options.RoutingPutOption) error
16 }
core/coreiface/tests/api.go
+25 -12
@@ -11,21 +11,12 @@ import (
11
12 var errAPINotImplemented = errors.New("api not implemented")
13
14 -func (tp *TestSuite) makeAPI(ctx context.Context) (coreiface.CoreAPI, error) {
15 - api, err := tp.MakeAPISwarm(ctx, false, 1)
16 - if err != nil {
17 - return nil, err
18 - }
19 -
20 - return api[0], nil
21 -}
22 -
14 type Provider interface {
15 // Make creates n nodes. fullIdentity set to false can be ignored
25 - MakeAPISwarm(ctx context.Context, fullIdentity bool, n int) ([]coreiface.CoreAPI, error)
16 + MakeAPISwarm(ctx context.Context, fullIdentity bool, online bool, n int) ([]coreiface.CoreAPI, error)
17 }
18
28 -func (tp *TestSuite) MakeAPISwarm(ctx context.Context, fullIdentity bool, n int) ([]coreiface.CoreAPI, error) {
19 +func (tp *TestSuite) makeAPISwarm(ctx context.Context, fullIdentity bool, online bool, n int) ([]coreiface.CoreAPI, error) {
20 if tp.apis != nil {
21 tp.apis <- 1
22 go func() {
@@ -34,7 +25,29 @@ func (tp *TestSuite) MakeAPISwarm(ctx context.Context, fullIdentity bool, n int)
25 }()
26 }
27
37 - return tp.Provider.MakeAPISwarm(ctx, fullIdentity, n)
28 + return tp.Provider.MakeAPISwarm(ctx, fullIdentity, online, n)
29 +}
30 +
31 +func (tp *TestSuite) makeAPI(ctx context.Context) (coreiface.CoreAPI, error) {
32 + api, err := tp.makeAPISwarm(ctx, false, false, 1)
33 + if err != nil {
34 + return nil, err
35 + }
36 +
37 + return api[0], nil
38 +}
39 +
40 +func (tp *TestSuite) makeAPIWithIdentityAndOffline(ctx context.Context) (coreiface.CoreAPI, error) {
41 + api, err := tp.makeAPISwarm(ctx, true, false, 1)
42 + if err != nil {
43 + return nil, err
44 + }
45 +
46 + return api[0], nil
47 +}
48 +
49 +func (tp *TestSuite) MakeAPISwarm(ctx context.Context, n int) ([]coreiface.CoreAPI, error) {
50 + return tp.makeAPISwarm(ctx, true, true, n)
51 }
52
53 type TestSuite struct {
core/coreiface/tests/dht.go
+3 -3
@@ -26,7 +26,7 @@ func (tp *TestSuite) TestDht(t *testing.T) {
26 func (tp *TestSuite) TestDhtFindPeer(t *testing.T) {
27 ctx, cancel := context.WithCancel(context.Background())
28 defer cancel()
29 - apis, err := tp.MakeAPISwarm(ctx, true, 5)
29 + apis, err := tp.MakeAPISwarm(ctx, 5)
30 if err != nil {
31 t.Fatal(err)
32 }
@@ -81,7 +81,7 @@ func (tp *TestSuite) TestDhtFindPeer(t *testing.T) {
81 func (tp *TestSuite) TestDhtFindProviders(t *testing.T) {
82 ctx, cancel := context.WithCancel(context.Background())
83 defer cancel()
84 - apis, err := tp.MakeAPISwarm(ctx, true, 5)
84 + apis, err := tp.MakeAPISwarm(ctx, 5)
85 if err != nil {
86 t.Fatal(err)
87 }
@@ -113,7 +113,7 @@ func (tp *TestSuite) TestDhtFindProviders(t *testing.T) {
113 func (tp *TestSuite) TestDhtProvide(t *testing.T) {
114 ctx, cancel := context.WithCancel(context.Background())
115 defer cancel()
116 - apis, err := tp.MakeAPISwarm(ctx, true, 5)
116 + apis, err := tp.MakeAPISwarm(ctx, 5)
117 if err != nil {
118 t.Fatal(err)
119 }
core/coreiface/tests/name.go
+3 -3
@@ -43,7 +43,7 @@ func (tp *TestSuite) TestPublishResolve(t *testing.T) {
43 ctx, cancel := context.WithCancel(context.Background())
44 defer cancel()
45 init := func() (coreiface.CoreAPI, path.Path) {
46 - apis, err := tp.MakeAPISwarm(ctx, true, 5)
46 + apis, err := tp.MakeAPISwarm(ctx, 5)
47 if err != nil {
48 t.Fatal(err)
49 return nil, nil
@@ -191,7 +191,7 @@ func (tp *TestSuite) TestPublishResolve(t *testing.T) {
191 func (tp *TestSuite) TestBasicPublishResolveKey(t *testing.T) {
192 ctx, cancel := context.WithCancel(context.Background())
193 defer cancel()
194 - apis, err := tp.MakeAPISwarm(ctx, true, 5)
194 + apis, err := tp.MakeAPISwarm(ctx, 5)
195 if err != nil {
196 t.Fatal(err)
197 }
@@ -235,7 +235,7 @@ func (tp *TestSuite) TestBasicPublishResolveTimeout(t *testing.T) {
235
236 ctx, cancel := context.WithCancel(context.Background())
237 defer cancel()
238 - apis, err := tp.MakeAPISwarm(ctx, true, 5)
238 + apis, err := tp.MakeAPISwarm(ctx, 5)
239 if err != nil {
240 t.Fatal(err)
241 }
core/coreiface/tests/pubsub.go
+1 -1
@@ -24,7 +24,7 @@ func (tp *TestSuite) TestBasicPubSub(t *testing.T) {
24 ctx, cancel := context.WithCancel(context.Background())
25 defer cancel()
26
27 - apis, err := tp.MakeAPISwarm(ctx, true, 2)
27 + apis, err := tp.MakeAPISwarm(ctx, 2)
28 if err != nil {
29 t.Fatal(err)
30 }
core/coreiface/tests/routing.go
+39 -4
@@ -7,6 +7,7 @@ import (
7
8 "github.com/gogo/protobuf/proto"
9 iface "github.com/ipfs/boxo/coreiface"
10 + "github.com/ipfs/boxo/coreiface/options"
11 ipns_pb "github.com/ipfs/boxo/ipns/pb"
12 )
13
@@ -20,15 +21,16 @@ func (tp *TestSuite) TestRouting(t *testing.T) {
21
22 t.Run("TestRoutingGet", tp.TestRoutingGet)
23 t.Run("TestRoutingPut", tp.TestRoutingPut)
24 + t.Run("TestRoutingPutOffline", tp.TestRoutingPutOffline)
25 }
26
25 -func (tp *TestSuite) testRoutingPublishKey(t *testing.T, ctx context.Context, api iface.CoreAPI) iface.IpnsEntry {
27 +func (tp *TestSuite) testRoutingPublishKey(t *testing.T, ctx context.Context, api iface.CoreAPI, opts ...options.NamePublishOption) iface.IpnsEntry {
28 p, err := addTestObject(ctx, api)
29 if err != nil {
30 t.Fatal(err)
31 }
32
31 - entry, err := api.Name().Publish(ctx, p)
33 + entry, err := api.Name().Publish(ctx, p, opts...)
34 if err != nil {
35 t.Fatal(err)
36 }
@@ -41,7 +43,7 @@ func (tp *TestSuite) TestRoutingGet(t *testing.T) {
43 ctx, cancel := context.WithCancel(context.Background())
44 defer cancel()
45
44 - apis, err := tp.MakeAPISwarm(ctx, true, 2)
46 + apis, err := tp.MakeAPISwarm(ctx, 2)
47 if err != nil {
48 t.Fatal(err)
49 }
@@ -70,7 +72,7 @@ func (tp *TestSuite) TestRoutingGet(t *testing.T) {
72 func (tp *TestSuite) TestRoutingPut(t *testing.T) {
73 ctx, cancel := context.WithCancel(context.Background())
74 defer cancel()
73 - apis, err := tp.MakeAPISwarm(ctx, true, 2)
75 + apis, err := tp.MakeAPISwarm(ctx, 2)
76 if err != nil {
77 t.Fatal(err)
78 }
@@ -90,3 +92,36 @@ func (tp *TestSuite) TestRoutingPut(t *testing.T) {
92 t.Fatal(err)
93 }
94 }
95 +
96 +func (tp *TestSuite) TestRoutingPutOffline(t *testing.T) {
97 + ctx, cancel := context.WithCancel(context.Background())
98 + defer cancel()
99 +
100 + // init a swarm & publish an IPNS entry to get a valid payload
101 + apis, err := tp.MakeAPISwarm(ctx, 2)
102 + if err != nil {
103 + t.Fatal(err)
104 + }
105 +
106 + ipnsEntry := tp.testRoutingPublishKey(t, ctx, apis[0], options.Name.AllowOffline(true))
107 + data, err := apis[0].Routing().Get(ctx, "/ipns/"+ipnsEntry.Name())
108 + if err != nil {
109 + t.Fatal(err)
110 + }
111 +
112 + // init our offline node and try to put the payload
113 + api, err := tp.makeAPIWithIdentityAndOffline(ctx)
114 + if err != nil {
115 + t.Fatal(err)
116 + }
117 +
118 + err = api.Routing().Put(ctx, "/ipns/"+ipnsEntry.Name(), data)
119 + if err == nil {
120 + t.Fatal("this operation should fail because we are offline")
121 + }
122 +
123 + err = api.Routing().Put(ctx, "/ipns/"+ipnsEntry.Name(), data, options.Put.AllowOffline(true))
124 + if err != nil {
125 + t.Fatal(err)
126 + }
127 +}