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
+}