ping WIP
License: MIT Signed-off-by: Brian Tiger Chow <brian@perfmode.com> Conflicts: core/commands/root.go begin ping command, WIP finish initial ping implementation
Brian Tiger Chow committed
Dec 4, 2014 at 21:31 UTC
069966d55a0f9ee7d6e1b6f084d54ce8a331f7f0
4 files changed
+116
core/commands/ping.go
new
+108
@@ -0,0 +1,108 @@
1
+package commands
2
+
3
+import (
4
+ "bytes"
5
+ "fmt"
6
+ "io"
7
+ "time"
8
+
9
+ cmds "github.com/jbenet/go-ipfs/commands"
10
+ peer "github.com/jbenet/go-ipfs/p2p/peer"
11
+ u "github.com/jbenet/go-ipfs/util"
12
+
13
+ context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
14
+)
15
+
16
+type PingResult struct {
17
+ Success bool
18
+ Time time.Duration
19
+}
20
+
21
+var PingCmd = &cmds.Command{
22
+ Helptext: cmds.HelpText{
23
+ Tagline: "send echo request packets to IPFS hosts",
24
+ Synopsis: `
25
+ipfs ping <peer.ID> - Send pings to a peer using the routing system to discover its address
26
+`,
27
+ ShortDescription: `
28
+ipfs ping is a tool to find a node (in the routing system),
29
+send pings, wait for pongs, and print out round-trip latency information.
30
+`,
31
+ },
32
+ Arguments: []cmds.Argument{
33
+ cmds.StringArg("peer-id", true, true, "ID of peer to ping"),
34
+ },
35
+ Marshalers: cmds.MarshalerMap{
36
+ cmds.Text: func(res cmds.Response) (io.Reader, error) {
37
+ outChan, ok := res.Output().(chan interface{})
38
+ if !ok {
39
+ return nil, u.ErrCast()
40
+ }
41
+
42
+ marshal := func(v interface{}) (io.Reader, error) {
43
+ obj, ok := v.(*PingResult)
44
+ if !ok {
45
+ return nil, u.ErrCast()
46
+ }
47
+
48
+ buf := new(bytes.Buffer)
49
+ if obj.Success {
50
+ fmt.Fprintf(buf, "Pong took %.2fms\n", obj.Time.Seconds()*1000)
51
+ } else {
52
+ fmt.Fprintf(buf, "Pong failed\n")
53
+ }
54
+ return buf, nil
55
+ }
56
+
57
+ return &cmds.ChannelMarshaler{
58
+ Channel: outChan,
59
+ Marshaler: marshal,
60
+ }, nil
61
+ },
62
+ },
63
+ Run: func(req cmds.Request) (interface{}, error) {
64
+ n, err := req.Context().GetNode()
65
+ if err != nil {
66
+ return nil, err
67
+ }
68
+
69
+ if !n.OnlineMode() {
70
+ return nil, errNotOnline
71
+ }
72
+
73
+ peerID, err := peer.IDB58Decode("QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ")
74
+ if err != nil {
75
+ return nil, err
76
+ }
77
+ const kPingTimeout = 10 * time.Second
78
+ ctx, _ := context.WithTimeout(context.Background(), kPingTimeout)
79
+ p, err := n.Routing.FindPeer(ctx, peerID)
80
+ if err != nil {
81
+ return nil, err
82
+ }
83
+
84
+ outChan := make(chan interface{})
85
+
86
+ go func() {
87
+ defer close(outChan)
88
+ for i := 0; i < 10; i++ {
89
+ ctx, _ = context.WithTimeout(context.Background(), kPingTimeout)
90
+ before := time.Now()
91
+ err := n.Routing.Ping(ctx, p.ID)
92
+ if err != nil {
93
+ outChan <- &PingResult{}
94
+ break
95
+ }
96
+ took := time.Now().Sub(before)
97
+ outChan <- &PingResult{
98
+ Success: true,
99
+ Time: took,
100
+ }
101
+ time.Sleep(time.Second)
102
+ }
103
+ }()
104
+
105
+ return outChan, nil
106
+ },
107
+ Type: PingResult{},
108
+}
core/commands/root.go
+1
@@ -81,6 +81,7 @@ var rootSubcommands = map[string]*cmds.Command{
81
"pin": PinCmd,
82
"refs": RefsCmd,
83
"swarm": SwarmCmd,
84
+ "ping": PingCmd,
85
"update": UpdateCmd,
86
"version": VersionCmd,
87
}
routing/mock/centralized_client.go
+4
@@ -79,4 +79,8 @@ func (c *client) Provide(_ context.Context, key u.Key) error {
79
return c.server.Announce(info, key)
80
}
81
82
+func (c *client) Ping(ctx context.Context, p peer.ID) error {
83
+ return nil
84
+}
85
+
86
var _ routing.IpfsRouting = &client{}
routing/routing.go
+3
@@ -36,4 +36,7 @@ type IpfsRouting interface {
36
// FindPeer searches for a peer with given ID, returns a peer.PeerInfo
37
// with relevant addresses.
38
FindPeer(context.Context, peer.ID) (peer.PeerInfo, error)
39
+
40
+ // Ping a peer, log the time it took
41
+ Ping(context.Context, peer.ID) error
42
}