cmds2: changed how the ctx.Node works
Juan Batiz-Benet committed
Nov 12, 2014 at 22:37 UTC
d18902df27d5b0e1c1b2e562a409b80185797897
17 files changed
+222
-77
cmd/ipfs2/daemon.go
+14
-7
@@ -22,21 +22,28 @@ var daemonCmd = &cmds.Command{
22
}
23
24
func daemonFunc(req cmds.Request) (interface{}, error) {
25
- ctx := req.Context()
26
-
27
- lock, err := daemon.Lock(ctx.ConfigRoot)
25
+ lock, err := daemon.Lock(req.Context().ConfigRoot)
26
if err != nil {
27
return nil, fmt.Errorf("Couldn't obtain lock. Is another daemon already running?")
28
}
29
defer lock.Close()
30
33
- node, err := core.NewIpfsNode(ctx.Config, true)
31
+ cfg, err := req.Context().GetConfig()
32
+ if err != nil {
33
+ return nil, err
34
+ }
35
+
36
+ // setup function that constructs the context. we have to do it this way
37
+ // to play along with how the Context works and thus not expose its internals
38
+ req.Context().ConstructNode = func() (*core.IpfsNode, error) {
39
+ return core.NewIpfsNode(cfg, true)
40
+ }
41
+ node, err := req.Context().GetNode()
42
if err != nil {
43
return nil, err
44
}
37
- ctx.Node = node
45
39
- addr, err := ma.NewMultiaddr(ctx.Config.Addresses.API)
46
+ addr, err := ma.NewMultiaddr(cfg.Addresses.API)
47
if err != nil {
48
return nil, err
49
}
@@ -46,7 +53,7 @@ func daemonFunc(req cmds.Request) (interface{}, error) {
53
return nil, err
54
}
55
49
- cmdHandler := cmdsHttp.NewHandler(*ctx, commands.Root)
56
+ cmdHandler := cmdsHttp.NewHandler(*req.Context(), commands.Root)
57
http.Handle(cmdsHttp.ApiPath+"/", cmdHandler)
58
59
ifpsHandler := &ipfsHandler{node}
cmd/ipfs2/main.go
+43
-35
@@ -166,13 +166,10 @@ func (i *cmdInvocation) Parse(args []string) error {
166
return err
167
}
168
169
- conf, err := getConfig(configPath)
170
- if err != nil {
171
- return err
172
- }
169
+ // this sets up the function that will initialize the config lazily.
170
ctx := i.req.Context()
171
ctx.ConfigRoot = configPath
175
- ctx.Config = conf
172
+ ctx.LoadConfig = loadConfig
173
174
// if no encoding was specified by user, default to plaintext encoding
175
// (if command doesn't support plaintext, use JSON instead)
@@ -202,51 +199,62 @@ func (i *cmdInvocation) requestedHelp() (short bool, long bool, err error) {
199
func callCommand(req cmds.Request, root *cmds.Command) (cmds.Response, error) {
200
var res cmds.Response
201
205
- // TODO explain what it means when root == Root
206
- // @mappum o/
207
- if root == Root {
208
- res = root.Call(req)
202
+ local, found, err := req.Option("local").Bool()
203
+ if err != nil {
204
+ return nil, err
205
+ }
206
+ remote := !found || !local
207
210
- } else {
211
- local, found, err := req.Option("local").Bool()
208
+ log.Info("Checking if daemon is running...")
209
+ if remote && daemon.Locked(req.Context().ConfigRoot) {
210
+
211
+ cfg, err := req.Context().GetConfig()
212
if err != nil {
213
return nil, err
214
}
215
216
- remote := !found || !local
216
+ addr, err := ma.NewMultiaddr(cfg.Addresses.API)
217
+ if err != nil {
218
+ return nil, err
219
+ }
220
218
- log.Info("Checking if daemon is running...")
219
- if remote && daemon.Locked(req.Context().ConfigRoot) {
220
- addr, err := ma.NewMultiaddr(req.Context().Config.Addresses.API)
221
- if err != nil {
222
- return nil, err
223
- }
221
+ _, host, err := manet.DialArgs(addr)
222
+ if err != nil {
223
+ return nil, err
224
+ }
225
225
- _, host, err := manet.DialArgs(addr)
226
- if err != nil {
227
- return nil, err
228
- }
226
+ client := cmdsHttp.NewClient(host)
227
230
- client := cmdsHttp.NewClient(host)
228
+ res, err = client.Send(req)
229
+ if err != nil {
230
+ return nil, err
231
+ }
232
232
- res, err = client.Send(req)
233
- if err != nil {
234
- return nil, err
235
- }
233
+ } else {
234
+ log.Info("Executing command locally: daemon not running")
235
237
- } else {
238
- log.Info("Executing command locally: daemon not running")
239
- node, err := core.NewIpfsNode(req.Context().Config, false)
236
+ // this sets up the function that will initialize the node
237
+ // this is so that we can construct the node lazily.
238
+ ctx := req.Context()
239
+ ctx.ConstructNode = func() (*core.IpfsNode, error) {
240
+ cfg, err := ctx.GetConfig()
241
if err != nil {
242
return nil, err
243
}
243
- defer node.Close()
244
- req.Context().Node = node
244
+ return core.NewIpfsNode(cfg, false)
245
+ }
246
+
247
+ // Okay!!!!! NOW we can call the command.
248
+ res = root.Call(req)
249
246
- res = root.Call(req)
250
+ // let's not forget teardown. If a node was initialized, we must close it.
251
+ // Note that this means the underlying req.Context().Node variable is exposed.
252
+ // this is gross, and should be changed when we extract out the exec Context.
253
+ node := req.Context().NodeWithoutConstructing()
254
+ if node != nil {
255
+ node.Close()
256
}
257
}
249
-
258
return res, nil
259
}
260
@@ -275,7 +283,7 @@ func getConfigRoot(req cmds.Request) (string, error) {
283
return configPath, nil
284
}
285
278
-func getConfig(path string) (*config.Config, error) {
286
+func loadConfig(path string) (*config.Config, error) {
287
configFile, err := config.Filename(path)
288
if err != nil {
289
return nil, err
cmd/ipfs2/tour.go
+20
-5
@@ -32,7 +32,11 @@ IPFS very quickly. To start, run:
32
Run: func(req cmds.Request) (interface{}, error) {
33
34
out := new(bytes.Buffer)
35
- cfg := req.Context().Config
35
+ cfg, err := req.Context().GetConfig()
36
+ if err != nil {
37
+ return nil, err
38
+ }
39
+
40
strs, err := internal.CastToStrings(req.Arguments())
41
if err != nil {
42
return nil, err
@@ -57,8 +61,11 @@ var cmdIpfsTourNext = &cmds.Command{
61
62
Run: func(req cmds.Request) (interface{}, error) {
63
var w bytes.Buffer
60
- cfg := req.Context().Config
64
path := req.Context().ConfigRoot
65
+ cfg, err := req.Context().GetConfig()
66
+ if err != nil {
67
+ return nil, err
68
+ }
69
70
topic := tour.NextTopic(tour.TopicID(cfg.Tour.Last))
71
if err := tourShow(&w, topic); err != nil {
@@ -84,10 +91,13 @@ var cmdIpfsTourRestart = &cmds.Command{
91
92
Run: func(req cmds.Request) (interface{}, error) {
93
path := req.Context().ConfigRoot
87
- cfg := req.Context().Config
94
+ cfg, err := req.Context().GetConfig()
95
+ if err != nil {
96
+ return nil, err
97
+ }
98
99
cfg.Tour.Last = ""
90
- err := writeConfig(path, cfg)
100
+ err = writeConfig(path, cfg)
101
if err != nil {
102
return nil, err
103
}
@@ -99,8 +109,13 @@ var cmdIpfsTourList = &cmds.Command{
109
Description: "Show a list of IPFS Tour topics",
110
111
Run: func(req cmds.Request) (interface{}, error) {
112
+ cfg, err := req.Context().GetConfig()
113
+ if err != nil {
114
+ return nil, err
115
+ }
116
+
117
var w bytes.Buffer
103
- tourListCmd(&w, req.Context().Config)
118
+ tourListCmd(&w, cfg)
119
w.WriteTo(os.Stdout) // TODO use res.SetOutput(output)
120
return nil, nil
121
},
commands/request.go
+38
-2
@@ -15,8 +15,44 @@ type optMap map[string]interface{}
15
16
type Context struct {
17
ConfigRoot string
18
- Config *config.Config
19
- Node *core.IpfsNode
18
+
19
+ config *config.Config
20
+ LoadConfig func(path string) (*config.Config, error)
21
+
22
+ node *core.IpfsNode
23
+ ConstructNode func() (*core.IpfsNode, error)
24
+}
25
+
26
+// GetConfig returns the config of the current Command exection
27
+// context. It may load it with the providied function.
28
+func (c *Context) GetConfig() (*config.Config, error) {
29
+ var err error
30
+ if c.config == nil {
31
+ if c.LoadConfig == nil {
32
+ panic("nil LoadConfig function")
33
+ }
34
+ c.config, err = c.LoadConfig(c.ConfigRoot)
35
+ }
36
+ return c.config, err
37
+}
38
+
39
+// GetNode returns the node of the current Command exection
40
+// context. It may construct it with the providied function.
41
+func (c *Context) GetNode() (*core.IpfsNode, error) {
42
+ var err error
43
+ if c.node == nil {
44
+ if c.ConstructNode == nil {
45
+ panic("nil ConstructNode function")
46
+ }
47
+ c.node, err = c.ConstructNode()
48
+ }
49
+ return c.node, err
50
+}
51
+
52
+// NodeWithoutConstructing returns the underlying node variable
53
+// so that clients may close it.
54
+func (c *Context) NodeWithoutConstructing() *core.IpfsNode {
55
+ return c.node
56
}
57
58
// Request represents a call to a command from a consumer
core/commands2/add.go
+4
-1
@@ -43,7 +43,10 @@ remains to be implemented.
43
`,
44
Run: func(req cmds.Request) (interface{}, error) {
45
added := &AddOutput{}
46
- n := req.Context().Node
46
+ n, err := req.Context().GetNode()
47
+ if err != nil {
48
+ return nil, err
49
+ }
50
51
recursive, _, err := req.Option("r").Bool()
52
if err != nil {
core/commands2/block.go
+8
-2
@@ -40,7 +40,10 @@ It outputs to stdout, and <key> is a base58 encoded multihash.`,
40
cmds.StringArg("key", true, false, "The base58 multihash of an existing block to get"),
41
},
42
Run: func(req cmds.Request) (interface{}, error) {
43
- n := req.Context().Node
43
+ n, err := req.Context().GetNode()
44
+ if err != nil {
45
+ return nil, err
46
+ }
47
48
key, ok := req.Arguments()[0].(string)
49
if !ok {
@@ -76,7 +79,10 @@ It reads from stdin, and <key> is a base58 encoded multihash.`,
79
cmds.FileArg("data", true, false, "The data to be stored as an IPFS block"),
80
},
81
Run: func(req cmds.Request) (interface{}, error) {
79
- n := req.Context().Node
82
+ n, err := req.Context().GetNode()
83
+ if err != nil {
84
+ return nil, err
85
+ }
86
87
in, ok := req.Arguments()[0].(io.Reader)
88
if !ok {
core/commands2/bootstrap.go
+18
-3
@@ -54,7 +54,12 @@ in the bootstrap list).
54
return nil, err
55
}
56
57
- added, err := bootstrapAdd(filename, req.Context().Config, input)
57
+ cfg, err := req.Context().GetConfig()
58
+ if err != nil {
59
+ return nil, err
60
+ }
61
+
62
+ added, err := bootstrapAdd(filename, cfg, input)
63
if err != nil {
64
return nil, err
65
}
@@ -94,7 +99,12 @@ var bootstrapRemoveCmd = &cmds.Command{
99
return nil, err
100
}
101
97
- removed, err := bootstrapRemove(filename, req.Context().Config, input)
102
+ cfg, err := req.Context().GetConfig()
103
+ if err != nil {
104
+ return nil, err
105
+ }
106
+
107
+ removed, err := bootstrapRemove(filename, cfg, input)
108
if err != nil {
109
return nil, err
110
}
@@ -121,7 +131,12 @@ var bootstrapListCmd = &cmds.Command{
131
`,
132
133
Run: func(req cmds.Request) (interface{}, error) {
124
- peers := req.Context().Config.Bootstrap
134
+ cfg, err := req.Context().GetConfig()
135
+ if err != nil {
136
+ return nil, err
137
+ }
138
+
139
+ peers := cfg.Bootstrap
140
return &BootstrapOutput{peers}, nil
141
},
142
Type: &BootstrapOutput{},
core/commands2/cat.go
+5
-1
@@ -19,7 +19,11 @@ it contains.
19
cmds.StringArg("ipfs-path", true, true, "The path to the IPFS object(s) to be outputted"),
20
},
21
Run: func(req cmds.Request) (interface{}, error) {
22
- node := req.Context().Node
22
+ node, err := req.Context().GetNode()
23
+ if err != nil {
24
+ return nil, err
25
+ }
26
+
27
readers := make([]io.Reader, 0, len(req.Arguments()))
28
29
paths, err := internal.CastToStrings(req.Arguments())
core/commands2/diag.go
+4
-1
@@ -44,7 +44,10 @@ connected peers and latencies between them.
44
`,
45
46
Run: func(req cmds.Request) (interface{}, error) {
47
- n := req.Context().Node
47
+ n, err := req.Context().GetNode()
48
+ if err != nil {
49
+ return nil, err
50
+ }
51
52
if !n.OnlineMode() {
53
return nil, errNotOnline
core/commands2/ls.go
+4
-1
@@ -34,7 +34,10 @@ it contains, with the following format:
34
cmds.StringArg("ipfs-path", false, true, "The path to the IPFS object(s) to list links from"),
35
},
36
Run: func(req cmds.Request) (interface{}, error) {
37
- node := req.Context().Node
37
+ node, err := req.Context().GetNode()
38
+ if err != nil {
39
+ return nil, err
40
+ }
41
42
paths, err := internal.CastToStrings(req.Arguments())
43
if err != nil {
core/commands2/mount_unix.go
+15
-7
@@ -32,10 +32,18 @@ not be listable, as it is virtual. Accessing known paths directly.
32
cmds.StringOption("n", "The path where IPNS should be mounted\n(default is '/ipns')"),
33
},
34
Run: func(req cmds.Request) (interface{}, error) {
35
- ctx := req.Context()
35
+ cfg, err := req.Context().GetConfig()
36
+ if err != nil {
37
+ return nil, err
38
+ }
39
+
40
+ node, err := req.Context().GetNode()
41
+ if err != nil {
42
+ return nil, err
43
+ }
44
45
// error if we aren't running node in online mode
38
- if ctx.Node.Network == nil {
46
+ if node.Network == nil {
47
return nil, errNotOnline
48
}
49
@@ -48,9 +56,9 @@ not be listable, as it is virtual. Accessing known paths directly.
56
return nil, err
57
}
58
if !found {
51
- fsdir = ctx.Config.Mounts.IPFS // use default value
59
+ fsdir = cfg.Mounts.IPFS // use default value
60
}
53
- fsdone := mountIpfs(ctx.Node, fsdir)
61
+ fsdone := mountIpfs(node, fsdir)
62
63
// get default mount points
64
nsdir, found, err := req.Option("n").String()
@@ -58,10 +66,10 @@ not be listable, as it is virtual. Accessing known paths directly.
66
return nil, err
67
}
68
if !found {
61
- nsdir = ctx.Config.Mounts.IPNS // NB: be sure to not redeclare!
69
+ nsdir = cfg.Mounts.IPNS // NB: be sure to not redeclare!
70
}
71
64
- nsdone := mountIpns(ctx.Node, nsdir, fsdir)
72
+ nsdone := mountIpns(node, nsdir, fsdir)
73
74
// wait until mounts return an error (or timeout if successful)
75
select {
@@ -72,7 +80,7 @@ not be listable, as it is virtual. Accessing known paths directly.
80
81
// mounted successfully, we timed out with no errors
82
case <-time.After(mountTimeout):
75
- output := ctx.Config.Mounts
83
+ output := cfg.Mounts
84
return &output, nil
85
}
86
},
core/commands2/object.go
+16
-4
@@ -48,7 +48,10 @@ output is the raw data of the object.
48
cmds.StringArg("key", true, false, "Key of the object to retrieve, in base58-encoded multihash format"),
49
},
50
Run: func(req cmds.Request) (interface{}, error) {
51
- n := req.Context().Node
51
+ n, err := req.Context().GetNode()
52
+ if err != nil {
53
+ return nil, err
54
+ }
55
56
key, ok := req.Arguments()[0].(string)
57
if !ok {
@@ -68,7 +71,10 @@ It outputs to stdout, and <key> is a base58 encoded multihash.`,
71
cmds.StringArg("key", true, false, "Key of the object to retrieve, in base58-encoded multihash format"),
72
},
73
Run: func(req cmds.Request) (interface{}, error) {
71
- n := req.Context().Node
74
+ n, err := req.Context().GetNode()
75
+ if err != nil {
76
+ return nil, err
77
+ }
78
79
key, ok := req.Arguments()[0].(string)
80
if !ok {
@@ -96,7 +102,10 @@ This command outputs data in the following encodings:
102
cmds.StringArg("key", true, false, "Key of the object to retrieve\n(in base58-encoded multihash format)"),
103
},
104
Run: func(req cmds.Request) (interface{}, error) {
99
- n := req.Context().Node
105
+ n, err := req.Context().GetNode()
106
+ if err != nil {
107
+ return nil, err
108
+ }
109
110
key, ok := req.Arguments()[0].(string)
111
if !ok {
@@ -148,7 +157,10 @@ Data should be in the format specified by <encoding>.
157
cmds.StringArg("encoding", true, false, "Encoding type of <data>, either \"protobuf\" or \"json\""),
158
},
159
Run: func(req cmds.Request) (interface{}, error) {
151
- n := req.Context().Node
160
+ n, err := req.Context().GetNode()
161
+ if err != nil {
162
+ return nil, err
163
+ }
164
165
input, ok := req.Arguments()[0].(io.Reader)
166
if !ok {
core/commands2/pin.go
+8
-2
@@ -31,7 +31,10 @@ on disk.
31
cmds.BoolOption("recursive", "r", "Recursively pin the object linked to by the specified object(s)"),
32
},
33
Run: func(req cmds.Request) (interface{}, error) {
34
- n := req.Context().Node
34
+ n, err := req.Context().GetNode()
35
+ if err != nil {
36
+ return nil, err
37
+ }
38
39
// set recursive flag
40
recursive, found, err := req.Option("recursive").Bool()
@@ -70,7 +73,10 @@ collected if needed.
73
cmds.BoolOption("recursive", "r", "Recursively unpin the object linked to by the specified object(s)"),
74
},
75
Run: func(req cmds.Request) (interface{}, error) {
73
- n := req.Context().Node
76
+ n, err := req.Context().GetNode()
77
+ if err != nil {
78
+ return nil, err
79
+ }
80
81
// set recursive flag
82
recursive, found, err := req.Option("recursive").Bool()
core/commands2/publish.go
+4
-1
@@ -39,8 +39,11 @@ Publish a <ref> to another public key:
39
},
40
Run: func(req cmds.Request) (interface{}, error) {
41
log.Debug("Begin Publish")
42
+ n, err := req.Context().GetNode()
43
+ if err != nil {
44
+ return nil, err
45
+ }
46
43
- n := req.Context().Node
47
args := req.Arguments()
48
49
if n.Network == nil {
core/commands2/refs.go
+4
-1
@@ -32,7 +32,10 @@ Note: list all refs recursively with -r.`,
32
cmds.BoolOption("recursive", "r", "Recursively list links of child nodes"),
33
},
34
Run: func(req cmds.Request) (interface{}, error) {
35
- n := req.Context().Node
35
+ n, err := req.Context().GetNode()
36
+ if err != nil {
37
+ return nil, err
38
+ }
39
40
unique, found, err := req.Option("unique").Bool()
41
if err != nil {
core/commands2/resolve.go
+5
-1
@@ -33,7 +33,11 @@ Resolve te value of another name:
33
},
34
Run: func(req cmds.Request) (interface{}, error) {
35
36
- n := req.Context().Node
36
+ n, err := req.Context().GetNode()
37
+ if err != nil {
38
+ return nil, err
39
+ }
40
+
41
var name string
42
43
if n.Network == nil {
core/commands2/update.go
+12
-3
@@ -20,7 +20,10 @@ var updateCmd = &cmds.Command{
20
`,
21
22
Run: func(req cmds.Request) (interface{}, error) {
23
- n := req.Context().Node
23
+ n, err := req.Context().GetNode()
24
+ if err != nil {
25
+ return nil, err
26
+ }
27
return updateApply(n)
28
},
29
Type: &UpdateOutput{},
@@ -51,7 +54,10 @@ Nothing will be downloaded or installed.
54
`,
55
56
Run: func(req cmds.Request) (interface{}, error) {
54
- n := req.Context().Node
57
+ n, err := req.Context().GetNode()
58
+ if err != nil {
59
+ return nil, err
60
+ }
61
return updateCheck(n)
62
},
63
Type: &UpdateOutput{},
@@ -76,7 +82,10 @@ var updateLogCmd = &cmds.Command{
82
`,
83
84
Run: func(req cmds.Request) (interface{}, error) {
79
- n := req.Context().Node
85
+ n, err := req.Context().GetNode()
86
+ if err != nil {
87
+ return nil, err
88
+ }
89
return updateLog(n)
90
},
91
}