Corenet API: Move more logic away from commands
License: MIT Signed-off-by: Łukasz Magiera <magik6k@gmail.com>
Łukasz Magiera committed
Jun 2, 2017 at 15:57 UTC
eac71847bdbcd2e44f4eee7f8fc926f47e609085
6 files changed
+214
-149
core/commands/corenet.go
+23
-145
@@ -9,14 +9,10 @@ import (
9
"text/tabwriter"
10
11
cmds "github.com/ipfs/go-ipfs/commands"
12
- core "github.com/ipfs/go-ipfs/core"
13
- corenet "github.com/ipfs/go-ipfs/corenet"
12
+ "github.com/ipfs/go-ipfs/core"
13
cnet "github.com/ipfs/go-ipfs/corenet/net"
14
16
- net "gx/ipfs/QmRscs8KxrSmSv4iuevHv8JfuUzHBMoqiaHzxfDRiksd6e/go-libp2p-net"
17
- peerstore "gx/ipfs/QmXZSd1qR5BxZkPyuwfT5jpqQFScZccoZvDneXsKzCNHWX/go-libp2p-peerstore"
15
ma "gx/ipfs/QmcyqRMCAXVtYPS4DiBrA7sezL9rRGfW8Ctx7cywL4TXJj/go-multiaddr"
19
- manet "gx/ipfs/Qmf1Gq7N45Rpuw7ev47uWgH6dLPtdnvcMRNPkVBwqjLJg2/go-multiaddr-net"
16
)
17
18
// CorenetAppInfoOutput is output type of ls command
@@ -188,6 +184,12 @@ var corenetStreamsCmd = &cmds.Command{
184
var corenetListenCmd = &cmds.Command{
185
Helptext: cmds.HelpText{
186
Tagline: "Create application protocol listener and proxy to network multiaddr.",
187
+ ShortDescription: `
188
+Register a p2p connection handler and proxies the connections to a specified
189
+address.
190
+
191
+Note that the connections originate from the ipfs daemon process.
192
+ `,
193
},
194
Arguments: []cmds.Argument{
195
cmds.StringArg("Protocol", true, false, "Protocol identifier."),
@@ -212,7 +214,7 @@ var corenetListenCmd = &cmds.Command{
214
}
215
216
proto := "/app/" + req.Arguments()[0]
215
- if checkProtoExists(n.PeerHost.Mux().Protocols(), proto) {
217
+ if cnet.CheckProtoExists(n, proto) {
218
res.SetError(errors.New("protocol handler already registered"), cmds.ErrNormal)
219
return
220
}
@@ -223,25 +225,12 @@ var corenetListenCmd = &cmds.Command{
225
return
226
}
227
226
- listener, err := cnet.Listen(n, proto)
228
+ _, err = cnet.NewListener(n, proto, addr)
229
if err != nil {
230
res.SetError(err, cmds.ErrNormal)
231
return
232
}
233
232
- app := corenet.AppInfo{
233
- Identity: n.Identity,
234
- Protocol: proto,
235
- Address: addr,
236
- Closer: listener,
237
- Running: true,
238
- Registry: &n.Corenet.Apps,
239
- }
240
-
241
- go acceptStreams(n, &app, listener)
242
-
243
- n.Corenet.Apps.Register(&app)
244
-
234
// Successful response.
235
res.SetOutput(&CorenetAppInfoOutput{
236
Protocol: proto,
@@ -250,66 +239,17 @@ var corenetListenCmd = &cmds.Command{
239
},
240
}
241
253
-func checkProtoExists(protos []string, proto string) bool {
254
- for _, p := range protos {
255
- if p != proto {
256
- continue
257
- }
258
- return true
259
- }
260
- return false
261
-}
262
-
263
-func acceptStreams(n *core.IpfsNode, app *corenet.AppInfo, listener cnet.Listener) {
264
- for app.Running {
265
- remote, err := listener.Accept()
266
- if err != nil {
267
- listener.Close()
268
- break
269
- }
270
-
271
- local, err := manet.Dial(app.Address)
272
- if err != nil {
273
- remote.Close()
274
- continue
275
- }
276
-
277
- stream := corenet.StreamInfo{
278
- Protocol: app.Protocol,
279
-
280
- LocalPeer: app.Identity,
281
- LocalAddr: app.Address,
282
-
283
- RemotePeer: remote.Conn().RemotePeer(),
284
- RemoteAddr: remote.Conn().RemoteMultiaddr(),
285
-
286
- Local: local,
287
- Remote: remote,
288
-
289
- Registry: &n.Corenet.Streams,
290
- }
291
-
292
- n.Corenet.Streams.Register(&stream)
293
- startStreaming(&stream)
294
- }
295
- n.Corenet.Apps.Deregister(app.Protocol)
296
-}
297
-
298
-func startStreaming(stream *corenet.StreamInfo) {
299
- go func() {
300
- io.Copy(stream.Local, stream.Remote)
301
- stream.Close()
302
- }()
303
-
304
- go func() {
305
- io.Copy(stream.Remote, stream.Local)
306
- stream.Close()
307
- }()
308
-}
309
-
242
var corenetDialCmd = &cmds.Command{
243
Helptext: cmds.HelpText{
244
Tagline: "Dial to an application service.",
245
+
246
+ ShortDescription: `
247
+Establish a new connection to a peer service.
248
+
249
+When a connection is made to a peer service the ipfs daemon will setup one time
250
+TCP listener and return it's bind port, this way a dialing application can
251
+transparently connect to a corenet service.
252
+ `,
253
},
254
Arguments: []cmds.Argument{
255
cmds.StringArg("Peer", true, false, "Remote peer to connect to"),
@@ -351,47 +291,12 @@ var corenetDialCmd = &cmds.Command{
291
}
292
}
293
354
- lnet, _, err := manet.DialArgs(bindAddr)
294
+ app, err := cnet.Dial(n, addr, peer, proto, bindAddr)
295
if err != nil {
296
res.SetError(err, cmds.ErrNormal)
297
return
298
}
299
360
- app := corenet.AppInfo{
361
- Identity: n.Identity,
362
- Protocol: proto,
363
- }
364
-
365
- n.Peerstore.AddAddr(peer, addr, peerstore.TempAddrTTL)
366
-
367
- remote, err := cnet.Dial(n, peer, proto)
368
- if err != nil {
369
- res.SetError(err, cmds.ErrNormal)
370
- return
371
- }
372
-
373
- switch lnet {
374
- case "tcp", "tcp4", "tcp6":
375
- listener, err := manet.Listen(bindAddr)
376
- if err != nil {
377
- res.SetError(err, cmds.ErrNormal)
378
- if err := remote.Close(); err != nil {
379
- res.SetError(err, cmds.ErrNormal)
380
- }
381
- return
382
- }
383
-
384
- app.Address = listener.Multiaddr()
385
- app.Closer = listener
386
- app.Running = true
387
-
388
- go doAccept(n, &app, remote, listener)
389
-
390
- default:
391
- res.SetError(errors.New("unsupported protocol: "+lnet), cmds.ErrNormal)
392
- return
393
- }
394
-
300
output := CorenetAppInfoOutput{
301
Protocol: app.Protocol,
302
Address: app.Address.String(),
@@ -401,33 +306,6 @@ var corenetDialCmd = &cmds.Command{
306
},
307
}
308
404
-func doAccept(n *core.IpfsNode, app *corenet.AppInfo, remote net.Stream, listener manet.Listener) {
405
- defer listener.Close()
406
-
407
- local, err := listener.Accept()
408
- if err != nil {
409
- return
410
- }
411
-
412
- stream := corenet.StreamInfo{
413
- Protocol: app.Protocol,
414
-
415
- LocalPeer: app.Identity,
416
- LocalAddr: app.Address,
417
-
418
- RemotePeer: remote.Conn().RemotePeer(),
419
- RemoteAddr: remote.Conn().RemoteMultiaddr(),
420
-
421
- Local: local,
422
- Remote: remote,
423
-
424
- Registry: &n.Corenet.Streams,
425
- }
426
-
427
- n.Corenet.Streams.Register(&stream)
428
- startStreaming(&stream)
429
-}
430
-
309
var corenetCloseCmd = &cmds.Command{
310
Helptext: cmds.HelpText{
311
Tagline: "Closes an active stream listener or client.",
@@ -464,15 +342,15 @@ var corenetCloseCmd = &cmds.Command{
342
343
useHandlerID := false
344
467
- if !closeAll && len(req.Arguments()) == 0 {
468
- res.SetError(errors.New("no handlerID nor stream protocol specified"), cmds.ErrNormal)
469
- return
345
+ if !closeAll {
346
+ if len(req.Arguments()) == 0 {
347
+ res.SetError(errors.New("no handlerID nor stream protocol specified"), cmds.ErrNormal)
348
+ return
349
+ }
350
471
- } else if !closeAll {
351
handlerID, err = strconv.ParseUint(req.Arguments()[0], 10, 64)
352
if err != nil {
353
proto = "/app/" + req.Arguments()[0]
475
-
354
} else {
355
useHandlerID = true
356
}
corenet/apps.go
+7
-3
@@ -5,6 +5,7 @@ import (
5
6
ma "gx/ipfs/QmcyqRMCAXVtYPS4DiBrA7sezL9rRGfW8Ctx7cywL4TXJj/go-multiaddr"
7
peer "gx/ipfs/QmdS9KpbDyPrieswibZhkod1oXqRwZJrUPzxCofAMWpFGq/go-libp2p-peer"
8
+ "fmt"
9
)
10
11
// AppInfo holds information on a local application protocol listener service.
@@ -30,9 +31,9 @@ type AppInfo struct {
31
32
// Close closes the listener. Does not affect child streams
33
func (c *AppInfo) Close() error {
33
- c.Registry.Deregister(c.Protocol)
34
c.Closer.Close()
35
- return nil
35
+ err := c.Registry.Deregister(c.Protocol)
36
+ return err
37
}
38
39
// AppRegistry is a collection of local application protocol listeners.
@@ -46,7 +47,7 @@ func (c *AppRegistry) Register(appInfo *AppInfo) {
47
}
48
49
// Deregister deregisters protocol handler from this registry
49
-func (c *AppRegistry) Deregister(proto string) {
50
+func (c *AppRegistry) Deregister(proto string) error {
51
foundAt := -1
52
for i, a := range c.Apps {
53
if a.Protocol == proto {
@@ -57,5 +58,8 @@ func (c *AppRegistry) Deregister(proto string) {
58
59
if foundAt != -1 {
60
c.Apps = append(c.Apps[:foundAt], c.Apps[foundAt+1:]...)
61
+ return nil
62
}
63
+
64
+ return fmt.Errorf("failed to deregister proto %s", proto)
65
}
corenet/net/dial.go
new
+82
@@ -0,0 +1,82 @@
1
+package net
2
+
3
+import (
4
+ "errors"
5
+
6
+ core "github.com/ipfs/go-ipfs/core"
7
+ corenet "github.com/ipfs/go-ipfs/corenet"
8
+
9
+ net "gx/ipfs/QmRscs8KxrSmSv4iuevHv8JfuUzHBMoqiaHzxfDRiksd6e/go-libp2p-net"
10
+ peerstore "gx/ipfs/QmXZSd1qR5BxZkPyuwfT5jpqQFScZccoZvDneXsKzCNHWX/go-libp2p-peerstore"
11
+ ma "gx/ipfs/QmcyqRMCAXVtYPS4DiBrA7sezL9rRGfW8Ctx7cywL4TXJj/go-multiaddr"
12
+ peer "gx/ipfs/QmdS9KpbDyPrieswibZhkod1oXqRwZJrUPzxCofAMWpFGq/go-libp2p-peer"
13
+ manet "gx/ipfs/Qmf1Gq7N45Rpuw7ev47uWgH6dLPtdnvcMRNPkVBwqjLJg2/go-multiaddr-net"
14
+)
15
+
16
+func Dial(n *core.IpfsNode, addr ma.Multiaddr, peer peer.ID, proto string, bindAddr ma.Multiaddr) (*corenet.AppInfo, error) {
17
+ lnet, _, err := manet.DialArgs(bindAddr)
18
+ if err != nil {
19
+ return nil, err
20
+ }
21
+
22
+ app := corenet.AppInfo{
23
+ Identity: n.Identity,
24
+ Protocol: proto,
25
+ }
26
+
27
+ n.Peerstore.AddAddr(peer, addr, peerstore.TempAddrTTL)
28
+
29
+ remote, err := dial(n, peer, proto)
30
+ if err != nil {
31
+ return nil, err
32
+ }
33
+
34
+ switch lnet {
35
+ case "tcp", "tcp4", "tcp6":
36
+ listener, err := manet.Listen(bindAddr)
37
+ if err != nil {
38
+ if err2 := remote.Close(); err2 != nil {
39
+ return nil, err2
40
+ }
41
+ return nil, err
42
+ }
43
+
44
+ app.Address = listener.Multiaddr()
45
+ app.Closer = listener
46
+ app.Running = true
47
+
48
+ go doAccept(n, &app, remote, listener)
49
+
50
+ default:
51
+ return nil, errors.New("unsupported protocol: " + lnet)
52
+ }
53
+
54
+ return &app, nil
55
+}
56
+
57
+func doAccept(n *core.IpfsNode, app *corenet.AppInfo, remote net.Stream, listener manet.Listener) {
58
+ defer listener.Close()
59
+
60
+ local, err := listener.Accept()
61
+ if err != nil {
62
+ return
63
+ }
64
+
65
+ stream := corenet.StreamInfo{
66
+ Protocol: app.Protocol,
67
+
68
+ LocalPeer: app.Identity,
69
+ LocalAddr: app.Address,
70
+
71
+ RemotePeer: remote.Conn().RemotePeer(),
72
+ RemoteAddr: remote.Conn().RemoteMultiaddr(),
73
+
74
+ Local: local,
75
+ Remote: remote,
76
+
77
+ Registry: &n.Corenet.Streams,
78
+ }
79
+
80
+ n.Corenet.Streams.Register(&stream)
81
+ startStreaming(&stream)
82
+}
corenet/net/listen.go
new
+67
@@ -0,0 +1,67 @@
1
+package net
2
+
3
+import (
4
+ "github.com/ipfs/go-ipfs/core"
5
+ "github.com/ipfs/go-ipfs/corenet"
6
+
7
+ ma "gx/ipfs/QmcyqRMCAXVtYPS4DiBrA7sezL9rRGfW8Ctx7cywL4TXJj/go-multiaddr"
8
+ manet "gx/ipfs/Qmf1Gq7N45Rpuw7ev47uWgH6dLPtdnvcMRNPkVBwqjLJg2/go-multiaddr-net"
9
+)
10
+
11
+// NewListener creates new corenet listener
12
+func NewListener(n *core.IpfsNode, proto string, addr ma.Multiaddr) (*corenet.AppInfo, error) {
13
+ listener, err := Listen(n, proto)
14
+ if err != nil {
15
+ return nil, err
16
+ }
17
+
18
+ app := corenet.AppInfo{
19
+ Identity: n.Identity,
20
+ Protocol: proto,
21
+ Address: addr,
22
+ Closer: listener,
23
+ Running: true,
24
+ Registry: &n.Corenet.Apps,
25
+ }
26
+
27
+ go acceptStreams(n, &app, listener)
28
+
29
+ n.Corenet.Apps.Register(&app)
30
+
31
+ return &app, nil
32
+}
33
+
34
+func acceptStreams(n *core.IpfsNode, app *corenet.AppInfo, listener Listener) {
35
+ for app.Running {
36
+ remote, err := listener.Accept()
37
+ if err != nil {
38
+ listener.Close()
39
+ break
40
+ }
41
+
42
+ local, err := manet.Dial(app.Address)
43
+ if err != nil {
44
+ remote.Close()
45
+ continue
46
+ }
47
+
48
+ stream := corenet.StreamInfo{
49
+ Protocol: app.Protocol,
50
+
51
+ LocalPeer: app.Identity,
52
+ LocalAddr: app.Address,
53
+
54
+ RemotePeer: remote.Conn().RemotePeer(),
55
+ RemoteAddr: remote.Conn().RemoteMultiaddr(),
56
+
57
+ Local: local,
58
+ Remote: remote,
59
+
60
+ Registry: &n.Corenet.Streams,
61
+ }
62
+
63
+ n.Corenet.Streams.Register(&stream)
64
+ startStreaming(&stream)
65
+ }
66
+ n.Corenet.Apps.Deregister(app.Protocol)
67
+}
corenet/net/net.go
+16
-1
@@ -5,6 +5,7 @@ import (
5
6
context "context"
7
core "github.com/ipfs/go-ipfs/core"
8
+
9
net "gx/ipfs/QmRscs8KxrSmSv4iuevHv8JfuUzHBMoqiaHzxfDRiksd6e/go-libp2p-net"
10
pstore "gx/ipfs/QmXZSd1qR5BxZkPyuwfT5jpqQFScZccoZvDneXsKzCNHWX/go-libp2p-peerstore"
11
pro "gx/ipfs/QmZNkThpqfVXs9GNbexPrfBbXSLNYeKrE7jwFM2oqHbyqN/go-libp2p-protocol"
@@ -67,7 +68,7 @@ func Listen(nd *core.IpfsNode, protocol string) (*IpfsListener, error) {
68
}
69
70
// Dial dials to a specified node and protocol
70
-func Dial(nd *core.IpfsNode, p peer.ID, protocol string) (net.Stream, error) {
71
+func dial(nd *core.IpfsNode, p peer.ID, protocol string) (net.Stream, error) {
72
ctx, cancel := context.WithTimeout(nd.Context(), time.Second*30)
73
defer cancel()
74
err := nd.PeerHost.Connect(ctx, pstore.PeerInfo{ID: p})
@@ -76,3 +77,17 @@ func Dial(nd *core.IpfsNode, p peer.ID, protocol string) (net.Stream, error) {
77
}
78
return nd.PeerHost.NewStream(nd.Context(), p, pro.ID(protocol))
79
}
80
+
81
+// CheckProtoExists checks whether a protocol handler is registered to
82
+// mux handler
83
+func CheckProtoExists(n *core.IpfsNode, proto string) bool {
84
+ protos := n.PeerHost.Mux().Protocols()
85
+
86
+ for _, p := range protos {
87
+ if p != proto {
88
+ continue
89
+ }
90
+ return true
91
+ }
92
+ return false
93
+}
corenet/net/util.go
new
+19
@@ -0,0 +1,19 @@
1
+package net
2
+
3
+import (
4
+ "io"
5
+
6
+ corenet "github.com/ipfs/go-ipfs/corenet"
7
+)
8
+
9
+func startStreaming(stream *corenet.StreamInfo) {
10
+ go func() {
11
+ io.Copy(stream.Local, stream.Remote)
12
+ stream.Close()
13
+ }()
14
+
15
+ go func() {
16
+ io.Copy(stream.Remote, stream.Local)
17
+ stream.Close()
18
+ }()
19
+}