routing.go 4.3 KB
Newer Older
tavit ohanian's avatar
tavit ohanian committed
1
// Package routing provides interfaces for peer routing and content routing in p2p.
2 3 4 5 6 7
package routing

import (
	"context"
	"errors"

tavit ohanian's avatar
tavit ohanian committed
8 9
	ci "gitlab.dms3.io/p2p/go-p2p-core/crypto"
	"gitlab.dms3.io/p2p/go-p2p-core/peer"
10

11
	cid "gitlab.dms3.io/dms3/go-cid"
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
)

// ErrNotFound is returned when the router fails to find the requested record.
var ErrNotFound = errors.New("routing: not found")

// ErrNotSupported is returned when the router doesn't support the given record
// type/operation.
var ErrNotSupported = errors.New("routing: operation or key not supported")

// ContentRouting is a value provider layer of indirection. It is used to find
// information about who has what content.
//
// Content is identified by CID (content identifier), which encodes a hash
// of the identified content in a future-proof manner.
type ContentRouting interface {
	// Provide adds the given cid to the content routing system. If 'true' is
	// passed, it also announces it, otherwise it is just kept in the local
	// accounting of which objects are being provided.
	Provide(context.Context, cid.Cid, bool) error

	// Search for peers who are able to provide a given key
Steven Allen's avatar
Steven Allen committed
33 34 35
	//
	// When count is 0, this method will return an unbounded number of
	// results.
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
	FindProvidersAsync(context.Context, cid.Cid, int) <-chan peer.AddrInfo
}

// PeerRouting is a way to find address information about certain peers.
// This can be implemented by a simple lookup table, a tracking server,
// or even a DHT.
type PeerRouting interface {
	// FindPeer searches for a peer with given ID, returns a peer.AddrInfo
	// with relevant addresses.
	FindPeer(context.Context, peer.ID) (peer.AddrInfo, error)
}

// ValueStore is a basic Put/Get interface.
type ValueStore interface {

	// PutValue adds value corresponding to given Key.
	PutValue(context.Context, string, []byte, ...Option) error

	// GetValue searches for the value corresponding to given Key.
	GetValue(context.Context, string, ...Option) ([]byte, error)

	// SearchValue searches for better and better values from this value
	// store corresponding to the given Key. By default implementations must
	// stop the search after a good value is found. A 'good' value is a value
	// that would be returned from GetValue.
	//
	// Useful when you want a result *now* but still want to hear about
	// better/newer results.
	//
	// Implementations of this methods won't return ErrNotFound. When a value
	// couldn't be found, the channel will get closed without passing any results
	SearchValue(context.Context, string, ...Option) (<-chan []byte, error)
}

tavit ohanian's avatar
tavit ohanian committed
70
// Routing is the combination of different routing types supported by p2p.
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
// It can be satisfied by a single item (such as a DHT) or multiple different
// pieces that are more optimized to each task.
type Routing interface {
	ContentRouting
	PeerRouting
	ValueStore

	// Bootstrap allows callers to hint to the routing system to get into a
	// Boostrapped state and remain there. It is not a synchronous call.
	Bootstrap(context.Context) error

	// TODO expose io.Closer or plain-old Close error
}

// PubKeyFetcher is an interfaces that should be implemented by value stores
// that can optimize retrieval of public keys.
//
tavit ohanian's avatar
tavit ohanian committed
88
// TODO(steb): Consider removing, see https://gitlab.dms3.io/p2p/go-p2p-routing/issues/22.
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
type PubKeyFetcher interface {
	// GetPublicKey returns the public key for the given peer.
	GetPublicKey(context.Context, peer.ID) (ci.PubKey, error)
}

// KeyForPublicKey returns the key used to retrieve public keys
// from a value store.
func KeyForPublicKey(id peer.ID) string {
	return "/pk/" + string(id)
}

// GetPublicKey retrieves the public key associated with the given peer ID from
// the value store.
//
// If the ValueStore is also a PubKeyFetcher, this method will call GetPublicKey
// (which may be better optimized) instead of GetValue.
func GetPublicKey(r ValueStore, ctx context.Context, p peer.ID) (ci.PubKey, error) {
	switch k, err := p.ExtractPublicKey(); err {
	case peer.ErrNoPublicKey:
		// check the datastore
	case nil:
		return k, nil
	default:
		return nil, err
	}

	if dht, ok := r.(PubKeyFetcher); ok {
		// If we have a DHT as our routing system, use optimized fetcher
		return dht.GetPublicKey(ctx, p)
	}
	key := KeyForPublicKey(p)
	pkval, err := r.GetValue(ctx, key)
	if err != nil {
		return nil, err
	}

	// get PublicKey from node.Data
	return ci.UnmarshalPublicKey(pkval)
}