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{}