coreapi: global offline option
License: MIT Signed-off-by: Łukasz Magiera <magik6k@gmail.com>
Łukasz Magiera committed
Dec 6, 2018 at 22:25 UTC
c832a32a4c5b6633df9efe4793edb837317ed9fd
11 files changed
+149
-65
commands/context.go
+4
-1
@@ -68,7 +68,10 @@ func (c *Context) GetAPI() (coreiface.CoreAPI, error) {
68
if err != nil {
69
return nil, err
70
}
71
- c.api = coreapi.NewCoreAPI(n)
71
+ c.api, err = coreapi.NewCoreAPI(n)
72
+ if err != nil {
73
+ return nil, err
74
+ }
75
}
76
return c.api, nil
77
}
core/coreapi/coreapi.go
+80
-37
@@ -16,26 +16,27 @@ package coreapi
16
import (
17
"context"
18
"errors"
19
-
20
- core "github.com/ipfs/go-ipfs/core"
19
+ "fmt"
20
+ "github.com/ipfs/go-ipfs/core"
21
coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
22
- options "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
23
- namesys "github.com/ipfs/go-ipfs/namesys"
24
- pin "github.com/ipfs/go-ipfs/pin"
25
- repo "github.com/ipfs/go-ipfs/repo"
22
+ "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
23
+ "github.com/ipfs/go-ipfs/namesys"
24
+ "github.com/ipfs/go-ipfs/pin"
25
+ "github.com/ipfs/go-ipfs/repo"
26
27
ci "gx/ipfs/QmNiJiXwWE3kRhZrC5ej3kSjWHm337pYfhjLGSCDNKJP2s/go-libp2p-crypto"
28
- exchange "gx/ipfs/QmP2g3VxmC7g7fyRJDj1VJ72KHZbJ9UW24YjSWEj1XTb4H/go-ipfs-exchange-interface"
28
+ "gx/ipfs/QmP2g3VxmC7g7fyRJDj1VJ72KHZbJ9UW24YjSWEj1XTb4H/go-ipfs-exchange-interface"
29
bserv "gx/ipfs/QmPoh3SrQzFBWtdGK6qmHDV4EanKR6kYPj4DD3J2NLoEmZ/go-blockservice"
30
- routing "gx/ipfs/QmRASJXJUFygM5qU4YrH7k7jD6S4Hg8nJmgqJ4bYJvLatd/go-libp2p-routing"
31
- blockstore "gx/ipfs/QmS2aqUZLJp8kF1ihE5rvDGE5LvmKDPnx32w9Z1BW9xLV5/go-ipfs-blockstore"
32
- peer "gx/ipfs/QmY5Grm8pJdiSSVsYxx4uNRgweY72EmYwuSDbRnbFok3iY/go-libp2p-peer"
30
+ "gx/ipfs/QmRASJXJUFygM5qU4YrH7k7jD6S4Hg8nJmgqJ4bYJvLatd/go-libp2p-routing"
31
+ "gx/ipfs/QmS2aqUZLJp8kF1ihE5rvDGE5LvmKDPnx32w9Z1BW9xLV5/go-ipfs-blockstore"
32
+ "gx/ipfs/QmY5Grm8pJdiSSVsYxx4uNRgweY72EmYwuSDbRnbFok3iY/go-libp2p-peer"
33
pstore "gx/ipfs/QmZ9zH2FnLcxv1xyzFeUpDUeo55xEhZQHgveZijcxr7TLj/go-libp2p-peerstore"
34
pubsub "gx/ipfs/QmaqGyUhWLsJbVo1QAujSu13mxNjFJ98Kt2VWGSnShGE1Q/go-libp2p-pubsub"
35
ipld "gx/ipfs/QmcKKBwfz6FyQdHR2jsXrrF6XeSBXYL86anmWNewpFpoF5/go-ipld-format"
36
logging "gx/ipfs/QmcuXC5cxs79ro2cUuHs4HQ2bkDLJUYokwL8aivcX6HW3C/go-log"
37
dag "gx/ipfs/QmdV35UHnL1FM52baPkeUo6u7Fxm2CRUkPTLRPxeF8a4Ap/go-merkledag"
38
- record "gx/ipfs/QmfARXVCzpwFXQdepAJZuqyNDgV9doEsMnVCo1ssmuSe1U/go-libp2p-record"
38
+ offlineroute "gx/ipfs/QmdmWkx54g7VfVyxeG8ic84uf4G6Eq1GohuyKA3XDuJ8oC/go-ipfs-routing/offline"
39
+ "gx/ipfs/QmfARXVCzpwFXQdepAJZuqyNDgV9doEsMnVCo1ssmuSe1U/go-libp2p-record"
40
p2phost "gx/ipfs/QmfD51tKgJiTMnW9JEiDiPwsCY4mqUoxkhKhBfyW12spTC/go-libp2p-host"
41
)
42
@@ -50,20 +51,20 @@ type CoreAPI struct {
51
repo repo.Repo
52
blockstore blockstore.GCBlockstore
53
baseBlocks blockstore.Blockstore
53
- blocks bserv.BlockService
54
- dag ipld.DAGService
54
pinning pin.Pinner
55
56
+ blocks bserv.BlockService
57
+ dag ipld.DAGService
58
+
59
peerstore pstore.Peerstore
60
peerHost p2phost.Host
59
- namesys namesys.NameSystem
61
recordValidator record.Validator
62
exchange exchange.Interface
63
63
- routing routing.IpfsRouting
64
- pubSub *pubsub.PubSub
64
+ namesys namesys.NameSystem
65
+ routing func(bool) (routing.IpfsRouting, error)
66
66
- checkRouting func(bool) error
67
+ pubSub *pubsub.PubSub
68
69
// TODO: this can be generalized to all functions when we implement some
70
// api based security mechanism
@@ -71,7 +72,12 @@ type CoreAPI struct {
72
}
73
74
// NewCoreAPI creates new instance of IPFS CoreAPI backed by go-ipfs Node.
74
-func NewCoreAPI(n *core.IpfsNode, opts ...options.ApiOption) coreiface.CoreAPI {
75
+func NewCoreAPI(n *core.IpfsNode, opts ...options.ApiOption) (coreiface.CoreAPI, error) {
76
+ settings, err := options.ApiOptions(opts...)
77
+ if err != nil {
78
+ return nil, err
79
+ }
80
+
81
api := &CoreAPI{
82
nctx: n.Context(),
83
@@ -81,38 +87,75 @@ func NewCoreAPI(n *core.IpfsNode, opts ...options.ApiOption) coreiface.CoreAPI {
87
repo: n.Repo,
88
blockstore: n.Blockstore,
89
baseBlocks: n.BaseBlocks,
84
- blocks: n.Blocks,
85
- dag: n.DAG,
90
pinning: n.Pinning,
91
92
+ blocks: n.Blocks,
93
+ dag: n.DAG,
94
+
95
peerstore: n.Peerstore,
96
peerHost: n.PeerHost,
97
namesys: n.Namesys,
98
recordValidator: n.RecordValidator,
99
exchange: n.Exchange,
100
94
- routing: n.Routing,
95
- pubSub: n.PubSub,
101
+ pubSub: n.PubSub,
102
+ }
103
97
- checkRouting: func(allowOffline bool) error {
98
- if !n.OnlineMode() {
99
- if !allowOffline {
100
- return coreiface.ErrOffline
101
- }
102
- return n.SetupOfflineRouting()
104
+ api.routing = func(allowOffline bool) (routing.IpfsRouting, error) {
105
+ if !n.OnlineMode() {
106
+ if !allowOffline {
107
+ return nil, coreiface.ErrOffline
108
}
104
- return nil
105
- },
106
-
107
- isPublishAllowed: func() error {
108
- if n.Mounts.Ipns != nil && n.Mounts.Ipns.IsActive() {
109
- return errors.New("cannot manually publish while IPNS is mounted")
109
+ if err := n.SetupOfflineRouting(); err != nil {
110
+ return nil, err
111
}
111
- return nil
112
- },
112
+ api.privateKey = n.PrivateKey
113
+ api.namesys = n.Namesys
114
+ return n.Routing, nil
115
+ }
116
+ if !settings.Offline {
117
+ return n.Routing, nil
118
+ }
119
+ if !allowOffline {
120
+ return nil, coreiface.ErrOffline
121
+ }
122
+
123
+ //todo: might want to cache this
124
+ cfg, err := n.Repo.Config()
125
+ if err != nil {
126
+ return nil, err
127
+ }
128
+
129
+ cs := cfg.Ipns.ResolveCacheSize
130
+ if cs == 0 {
131
+ cs = 128
132
+ }
133
+ if cs < 0 {
134
+ return nil, fmt.Errorf("cannot specify negative resolve cache size")
135
+ }
136
+
137
+ offroute := offlineroute.NewOfflineRouter(api.repo.Datastore(), api.recordValidator)
138
+ api.namesys = namesys.NewNameSystem(offroute, api.repo.Datastore(), cs)
139
+
140
+ return offroute, nil
141
+ }
142
+
143
+ api.isPublishAllowed = func() error {
144
+ if n.Mounts.Ipns != nil && n.Mounts.Ipns.IsActive() {
145
+ return errors.New("cannot manually publish while IPNS is mounted")
146
+ }
147
+ return nil
148
+ }
149
+
150
+ if settings.Offline {
151
+ api.peerstore = nil
152
+ api.peerHost = nil
153
+ api.namesys = nil
154
+ api.recordValidator = nil
155
+ api.exchange = nil
156
}
157
115
- return api
158
+ return api, nil
159
}
160
161
// Unixfs returns the UnixfsAPI interface implementation backed by the go-ipfs node
core/coreapi/dht.go
+17
-7
@@ -2,7 +2,6 @@ package coreapi
2
3
import (
4
"context"
5
- "errors"
5
"fmt"
6
7
coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
@@ -22,7 +21,12 @@ import (
21
type DhtAPI CoreAPI
22
23
func (api *DhtAPI) FindPeer(ctx context.Context, p peer.ID) (pstore.PeerInfo, error) {
25
- pi, err := api.routing.FindPeer(ctx, peer.ID(p))
24
+ r, err := api.routing(false)
25
+ if err != nil {
26
+ return pstore.PeerInfo{}, err
27
+ }
28
+
29
+ pi, err := r.FindPeer(ctx, peer.ID(p))
30
if err != nil {
31
return pstore.PeerInfo{}, err
32
}
@@ -36,6 +40,11 @@ func (api *DhtAPI) FindProviders(ctx context.Context, p coreiface.Path, opts ...
40
return nil, err
41
}
42
43
+ r, err := api.routing(false)
44
+ if err != nil {
45
+ return nil, err
46
+ }
47
+
48
rp, err := api.core().ResolvePath(ctx, p)
49
if err != nil {
50
return nil, err
@@ -46,7 +55,7 @@ func (api *DhtAPI) FindProviders(ctx context.Context, p coreiface.Path, opts ...
55
return nil, fmt.Errorf("number of providers must be greater than 0")
56
}
57
49
- pchan := api.routing.FindProvidersAsync(ctx, rp.Cid(), numProviders)
58
+ pchan := r.FindProvidersAsync(ctx, rp.Cid(), numProviders)
59
return pchan, nil
60
}
61
@@ -56,8 +65,9 @@ func (api *DhtAPI) Provide(ctx context.Context, path coreiface.Path, opts ...cao
65
return err
66
}
67
59
- if api.routing == nil {
60
- return errors.New("cannot provide in offline mode")
68
+ r, err := api.routing(false)
69
+ if err != nil {
70
+ return err
71
}
72
73
rp, err := api.core().ResolvePath(ctx, path)
@@ -77,9 +87,9 @@ func (api *DhtAPI) Provide(ctx context.Context, path coreiface.Path, opts ...cao
87
}
88
89
if settings.Recursive {
80
- err = provideKeysRec(ctx, api.routing, api.blockstore, []cid.Cid{c})
90
+ err = provideKeysRec(ctx, r, api.blockstore, []cid.Cid{c})
91
} else {
82
- err = provideKeys(ctx, api.routing, []cid.Cid{c})
92
+ err = provideKeys(ctx, r, []cid.Cid{c})
93
}
94
if err != nil {
95
return err
core/coreapi/name.go
+6
-3
@@ -47,7 +47,8 @@ func (api *NameAPI) Publish(ctx context.Context, p coreiface.Path, opts ...caopt
47
return nil, err
48
}
49
50
- if err := api.checkRouting(options.AllowOffline); err != nil {
50
+ _, err = api.routing(options.AllowOffline)
51
+ if err != nil {
52
return nil, err
53
}
54
@@ -88,7 +89,8 @@ func (api *NameAPI) Search(ctx context.Context, name string, opts ...caopts.Name
89
return nil, err
90
}
91
91
- if err := api.checkRouting(true); err != nil {
92
+ r, err := api.routing(true)
93
+ if err != nil {
94
return nil, err
95
}
96
@@ -98,13 +100,14 @@ func (api *NameAPI) Search(ctx context.Context, name string, opts ...caopts.Name
100
return nil, errors.New("cannot specify both local and nocache")
101
}
102
103
+ //TODO: can replaced with api.WithOpt(opts.Api.Offline(true))
104
if options.Local {
105
offroute := offline.NewOfflineRouter(api.repo.Datastore(), api.recordValidator)
106
resolver = namesys.NewIpnsResolver(offroute)
107
}
108
109
if !options.Cache {
107
- resolver = namesys.NewNameSystem(api.routing, api.repo.Datastore(), 0)
110
+ resolver = namesys.NewNameSystem(r, api.repo.Datastore(), 0)
111
}
112
113
if !strings.HasPrefix(name, "/ipns/") {
core/coreapi/pubsub.go
+16
-11
@@ -30,7 +30,8 @@ type pubSubMessage struct {
30
}
31
32
func (api *PubSubAPI) Ls(ctx context.Context) ([]string, error) {
33
- if err := api.checkNode(); err != nil {
33
+ _, err := api.checkNode()
34
+ if err != nil {
35
return nil, err
36
}
37
@@ -38,7 +39,8 @@ func (api *PubSubAPI) Ls(ctx context.Context) ([]string, error) {
39
}
40
41
func (api *PubSubAPI) Peers(ctx context.Context, opts ...caopts.PubSubPeersOption) ([]peer.ID, error) {
41
- if err := api.checkNode(); err != nil {
42
+ _, err := api.checkNode()
43
+ if err != nil {
44
return nil, err
45
}
46
@@ -58,7 +60,8 @@ func (api *PubSubAPI) Peers(ctx context.Context, opts ...caopts.PubSubPeersOptio
60
}
61
62
func (api *PubSubAPI) Publish(ctx context.Context, topic string, data []byte) error {
61
- if err := api.checkNode(); err != nil {
63
+ _, err := api.checkNode()
64
+ if err != nil {
65
return err
66
}
67
@@ -68,7 +71,8 @@ func (api *PubSubAPI) Publish(ctx context.Context, topic string, data []byte) er
71
func (api *PubSubAPI) Subscribe(ctx context.Context, topic string, opts ...caopts.PubSubSubscribeOption) (coreiface.PubSubSubscription, error) {
72
options, err := caopts.PubSubSubscribeOptions(opts...)
73
71
- if err := api.checkNode(); err != nil {
74
+ r, err := api.checkNode()
75
+ if err != nil {
76
return nil, err
77
}
78
@@ -87,7 +91,7 @@ func (api *PubSubAPI) Subscribe(ctx context.Context, topic string, opts ...caopt
91
return
92
}
93
90
- connectToPubSubPeers(pubctx, api.routing, api.peerHost, blk.Path().Cid())
94
+ connectToPubSubPeers(pubctx, r, api.peerHost, blk.Path().Cid())
95
}()
96
}
97
@@ -118,16 +122,17 @@ func connectToPubSubPeers(ctx context.Context, r routing.IpfsRouting, ph p2phost
122
wg.Wait()
123
}
124
121
-func (api *PubSubAPI) checkNode() error {
122
- if err := api.checkRouting(false); err != nil {
123
- return err
125
+func (api *PubSubAPI) checkNode() (routing.IpfsRouting, error) {
126
+ if api.pubSub == nil {
127
+ return nil, errors.New("experimental pubsub feature not enabled. Run daemon with --enable-pubsub-experiment to use.")
128
}
129
126
- if api.pubSub == nil {
127
- return errors.New("experimental pubsub feature not enabled. Run daemon with --enable-pubsub-experiment to use.")
130
+ r, err := api.routing(false)
131
+ if err != nil {
132
+ return nil, err
133
}
134
130
- return nil
135
+ return r, nil
136
}
137
138
func (sub *pubSubSubscription) Close() error {
core/coreapi/unixfs_test.go
+4
-1
@@ -102,7 +102,10 @@ func makeAPISwarm(ctx context.Context, fullIdentity bool, n int) ([]*core.IpfsNo
102
return nil, nil, err
103
}
104
nodes[i] = node
105
- apis[i] = coreapi.NewCoreAPI(node)
105
+ apis[i], err = coreapi.NewCoreAPI(node)
106
+ if err != nil {
107
+ return nil, nil, err
108
+ }
109
}
110
111
err := mn.LinkAll()
core/corehttp/gateway.go
+6
-1
@@ -25,11 +25,16 @@ func GatewayOption(writable bool, paths ...string) ServeOption {
25
return nil, err
26
}
27
28
+ api, err := coreapi.NewCoreAPI(n)
29
+ if err != nil {
30
+ return nil, err
31
+ }
32
+
33
gateway := newGatewayHandler(n, GatewayConfig{
34
Headers: cfg.Gateway.HTTPHeaders,
35
Writable: writable,
36
PathPrefixes: cfg.Gateway.PathPrefixes,
32
- }, coreapi.NewCoreAPI(n))
37
+ }, api)
38
39
for _, p := range paths {
40
mux.Handle(p+"/", gateway)
fuse/readonly/ipfs_test.go
+4
-1
@@ -118,7 +118,10 @@ func TestIpfsStressRead(t *testing.T) {
118
nd, mnt := setupIpfsTest(t, nil)
119
defer mnt.Close()
120
121
- api := coreapi.NewCoreAPI(nd)
121
+ api, err := coreapi.NewCoreAPI(nd)
122
+ if err != nil {
123
+ t.Fatal(err)
124
+ }
125
126
var nodes []ipld.Node
127
var paths []string
test/integration/addcat_test.go
+4
-1
@@ -120,7 +120,10 @@ func DirectAddCat(data []byte, conf testutil.LatencyConfig) error {
120
}
121
defer catter.Close()
122
123
- catterApi := coreapi.NewCoreAPI(catter)
123
+ catterApi, err := coreapi.NewCoreAPI(catter)
124
+ if err != nil {
125
+ return err
126
+ }
127
128
err = mn.LinkAll()
129
if err != nil {
test/integration/bench_cat_test.go
+4
-1
@@ -66,7 +66,10 @@ func benchCat(b *testing.B, data []byte, conf testutil.LatencyConfig) error {
66
}
67
defer catter.Close()
68
69
- catterApi := coreapi.NewCoreAPI(catter)
69
+ catterApi, err := coreapi.NewCoreAPI(catter)
70
+ if err != nil {
71
+ return err
72
+ }
73
74
err = mn.LinkAll()
75
if err != nil {
test/integration/three_legged_cat_test.go
+4
-1
@@ -103,7 +103,10 @@ func RunThreeLeggedCat(data []byte, conf testutil.LatencyConfig) error {
103
}
104
defer catter.Close()
105
106
- catterApi := coreapi.NewCoreAPI(catter)
106
+ catterApi, err := coreapi.NewCoreAPI(catter)
107
+ if err != nil {
108
+ return err
109
+ }
110
111
mn.LinkAll()
112