github.com/keltia/go-ipfs@v0.3.8-0.20150909044612-210793031c63/routing/supernode/client.go (about) 1 package supernode 2 3 import ( 4 "bytes" 5 "errors" 6 "time" 7 8 proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto" 9 context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" 10 11 key "github.com/ipfs/go-ipfs/blocks/key" 12 "github.com/ipfs/go-ipfs/p2p/host" 13 peer "github.com/ipfs/go-ipfs/p2p/peer" 14 routing "github.com/ipfs/go-ipfs/routing" 15 pb "github.com/ipfs/go-ipfs/routing/dht/pb" 16 proxy "github.com/ipfs/go-ipfs/routing/supernode/proxy" 17 eventlog "github.com/ipfs/go-ipfs/thirdparty/eventlog" 18 ) 19 20 var log = eventlog.Logger("supernode") 21 22 type Client struct { 23 peerhost host.Host 24 peerstore peer.Peerstore 25 proxy proxy.Proxy 26 local peer.ID 27 } 28 29 // TODO take in datastore/cache 30 func NewClient(px proxy.Proxy, h host.Host, ps peer.Peerstore, local peer.ID) (*Client, error) { 31 return &Client{ 32 proxy: px, 33 local: local, 34 peerstore: ps, 35 peerhost: h, 36 }, nil 37 } 38 39 func (c *Client) FindProvidersAsync(ctx context.Context, k key.Key, max int) <-chan peer.PeerInfo { 40 ctx = eventlog.ContextWithLoggable(ctx, eventlog.Uuid("findProviders")) 41 defer log.EventBegin(ctx, "findProviders", &k).Done() 42 ch := make(chan peer.PeerInfo) 43 go func() { 44 defer close(ch) 45 request := pb.NewMessage(pb.Message_GET_PROVIDERS, string(k), 0) 46 response, err := c.proxy.SendRequest(ctx, request) 47 if err != nil { 48 log.Debug(err) 49 return 50 } 51 for _, p := range pb.PBPeersToPeerInfos(response.GetProviderPeers()) { 52 select { 53 case <-ctx.Done(): 54 log.Debug(ctx.Err()) 55 return 56 case ch <- p: 57 } 58 } 59 }() 60 return ch 61 } 62 63 func (c *Client) PutValue(ctx context.Context, k key.Key, v []byte) error { 64 defer log.EventBegin(ctx, "putValue", &k).Done() 65 r, err := makeRecord(c.peerstore, c.local, k, v) 66 if err != nil { 67 return err 68 } 69 pmes := pb.NewMessage(pb.Message_PUT_VALUE, string(k), 0) 70 pmes.Record = r 71 return c.proxy.SendMessage(ctx, pmes) // wrap to hide the remote 72 } 73 74 func (c *Client) GetValue(ctx context.Context, k key.Key) ([]byte, error) { 75 defer log.EventBegin(ctx, "getValue", &k).Done() 76 msg := pb.NewMessage(pb.Message_GET_VALUE, string(k), 0) 77 response, err := c.proxy.SendRequest(ctx, msg) // TODO wrap to hide the remote 78 if err != nil { 79 return nil, err 80 } 81 return response.Record.GetValue(), nil 82 } 83 84 func (c *Client) Provide(ctx context.Context, k key.Key) error { 85 defer log.EventBegin(ctx, "provide", &k).Done() 86 msg := pb.NewMessage(pb.Message_ADD_PROVIDER, string(k), 0) 87 // FIXME how is connectedness defined for the local node 88 pri := []pb.PeerRoutingInfo{ 89 { 90 PeerInfo: peer.PeerInfo{ 91 ID: c.local, 92 Addrs: c.peerhost.Addrs(), 93 }, 94 }, 95 } 96 msg.ProviderPeers = pb.PeerRoutingInfosToPBPeers(pri) 97 return c.proxy.SendMessage(ctx, msg) // TODO wrap to hide remote 98 } 99 100 func (c *Client) FindPeer(ctx context.Context, id peer.ID) (peer.PeerInfo, error) { 101 defer log.EventBegin(ctx, "findPeer", id).Done() 102 request := pb.NewMessage(pb.Message_FIND_NODE, string(id), 0) 103 response, err := c.proxy.SendRequest(ctx, request) // hide remote 104 if err != nil { 105 return peer.PeerInfo{}, err 106 } 107 for _, p := range pb.PBPeersToPeerInfos(response.GetCloserPeers()) { 108 if p.ID == id { 109 return p, nil 110 } 111 } 112 return peer.PeerInfo{}, errors.New("could not find peer") 113 } 114 115 // creates and signs a record for the given key/value pair 116 func makeRecord(ps peer.Peerstore, p peer.ID, k key.Key, v []byte) (*pb.Record, error) { 117 blob := bytes.Join([][]byte{[]byte(k), v, []byte(p)}, []byte{}) 118 sig, err := ps.PrivKey(p).Sign(blob) 119 if err != nil { 120 return nil, err 121 } 122 return &pb.Record{ 123 Key: proto.String(string(k)), 124 Value: v, 125 Author: proto.String(string(p)), 126 Signature: sig, 127 }, nil 128 } 129 130 func (c *Client) Ping(ctx context.Context, id peer.ID) (time.Duration, error) { 131 defer log.EventBegin(ctx, "ping", id).Done() 132 return time.Nanosecond, errors.New("supernode routing does not support the ping method") 133 } 134 135 func (c *Client) Bootstrap(ctx context.Context) error { 136 return c.proxy.Bootstrap(ctx) 137 } 138 139 var _ routing.IpfsRouting = &Client{}