From 069966d55a0f9ee7d6e1b6f084d54ce8a331f7f0 Mon Sep 17 00:00:00 2001 From: Brian Tiger Chow Date: Thu, 4 Dec 2014 21:31:38 -0800 Subject: [PATCH] ping WIP License: MIT Signed-off-by: Brian Tiger Chow Conflicts: core/commands/root.go begin ping command, WIP finish initial ping implementation --- core/commands/ping.go | 108 +++++++++++++++++++++++++++++ core/commands/root.go | 1 + routing/mock/centralized_client.go | 4 ++ routing/routing.go | 3 + 4 files changed, 116 insertions(+) create mode 100644 core/commands/ping.go diff --git a/core/commands/ping.go b/core/commands/ping.go new file mode 100644 index 000000000..9eb039f1f --- /dev/null +++ b/core/commands/ping.go @@ -0,0 +1,108 @@ +package commands + +import ( + "bytes" + "fmt" + "io" + "time" + + cmds "github.com/jbenet/go-ipfs/commands" + peer "github.com/jbenet/go-ipfs/p2p/peer" + u "github.com/jbenet/go-ipfs/util" + + context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context" +) + +type PingResult struct { + Success bool + Time time.Duration +} + +var PingCmd = &cmds.Command{ + Helptext: cmds.HelpText{ + Tagline: "send echo request packets to IPFS hosts", + Synopsis: ` +ipfs ping - Send pings to a peer using the routing system to discover its address +`, + ShortDescription: ` +ipfs ping is a tool to find a node (in the routing system), +send pings, wait for pongs, and print out round-trip latency information. +`, + }, + Arguments: []cmds.Argument{ + cmds.StringArg("peer-id", true, true, "ID of peer to ping"), + }, + Marshalers: cmds.MarshalerMap{ + cmds.Text: func(res cmds.Response) (io.Reader, error) { + outChan, ok := res.Output().(chan interface{}) + if !ok { + return nil, u.ErrCast() + } + + marshal := func(v interface{}) (io.Reader, error) { + obj, ok := v.(*PingResult) + if !ok { + return nil, u.ErrCast() + } + + buf := new(bytes.Buffer) + if obj.Success { + fmt.Fprintf(buf, "Pong took %.2fms\n", obj.Time.Seconds()*1000) + } else { + fmt.Fprintf(buf, "Pong failed\n") + } + return buf, nil + } + + return &cmds.ChannelMarshaler{ + Channel: outChan, + Marshaler: marshal, + }, nil + }, + }, + Run: func(req cmds.Request) (interface{}, error) { + n, err := req.Context().GetNode() + if err != nil { + return nil, err + } + + if !n.OnlineMode() { + return nil, errNotOnline + } + + peerID, err := peer.IDB58Decode("QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ") + if err != nil { + return nil, err + } + const kPingTimeout = 10 * time.Second + ctx, _ := context.WithTimeout(context.Background(), kPingTimeout) + p, err := n.Routing.FindPeer(ctx, peerID) + if err != nil { + return nil, err + } + + outChan := make(chan interface{}) + + go func() { + defer close(outChan) + for i := 0; i < 10; i++ { + ctx, _ = context.WithTimeout(context.Background(), kPingTimeout) + before := time.Now() + err := n.Routing.Ping(ctx, p.ID) + if err != nil { + outChan <- &PingResult{} + break + } + took := time.Now().Sub(before) + outChan <- &PingResult{ + Success: true, + Time: took, + } + time.Sleep(time.Second) + } + }() + + return outChan, nil + }, + Type: PingResult{}, +} diff --git a/core/commands/root.go b/core/commands/root.go index 9ab6185a1..7318b5a19 100644 --- a/core/commands/root.go +++ b/core/commands/root.go @@ -81,6 +81,7 @@ var rootSubcommands = map[string]*cmds.Command{ "pin": PinCmd, "refs": RefsCmd, "swarm": SwarmCmd, + "ping": PingCmd, "update": UpdateCmd, "version": VersionCmd, } diff --git a/routing/mock/centralized_client.go b/routing/mock/centralized_client.go index 2aeafe026..da8e39692 100644 --- a/routing/mock/centralized_client.go +++ b/routing/mock/centralized_client.go @@ -79,4 +79,8 @@ func (c *client) Provide(_ context.Context, key u.Key) error { return c.server.Announce(info, key) } +func (c *client) Ping(ctx context.Context, p peer.ID) error { + return nil +} + var _ routing.IpfsRouting = &client{} diff --git a/routing/routing.go b/routing/routing.go index 1fbd79d25..934a00c41 100644 --- a/routing/routing.go +++ b/routing/routing.go @@ -36,4 +36,7 @@ type IpfsRouting interface { // FindPeer searches for a peer with given ID, returns a peer.PeerInfo // with relevant addresses. FindPeer(context.Context, peer.ID) (peer.PeerInfo, error) + + // Ping a peer, log the time it took + Ping(context.Context, peer.ID) error }