virtual.go 3.26 KB
Newer Older
Brian Tiger Chow's avatar
Brian Tiger Chow committed
1 2 3 4 5
package bitswap

import (
	"errors"

6
	key "github.com/ipfs/go-ipfs/blocks/key"
7 8 9 10 11
	bsmsg "github.com/ipfs/go-ipfs/exchange/bitswap/message"
	bsnet "github.com/ipfs/go-ipfs/exchange/bitswap/network"
	routing "github.com/ipfs/go-ipfs/routing"
	mockrouting "github.com/ipfs/go-ipfs/routing/mock"
	delay "github.com/ipfs/go-ipfs/thirdparty/delay"
12
	testutil "github.com/ipfs/go-ipfs/thirdparty/testutil"
Lars Gierth's avatar
Lars Gierth committed
13
	peer "gx/ipfs/QmYgaiNVVL7f2nydijAwpDRunRkmxfu3PoK87Y3pH84uAW/go-libp2p/p2p/peer"
Jeromy's avatar
Jeromy committed
14
	context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
Brian Tiger Chow's avatar
Brian Tiger Chow committed
15 16
)

17
func VirtualNetwork(rs mockrouting.Server, d delay.D) Network {
Brian Tiger Chow's avatar
Brian Tiger Chow committed
18
	return &network{
19 20
		clients:       make(map[peer.ID]bsnet.Receiver),
		delay:         d,
21
		routingserver: rs,
Brian Tiger Chow's avatar
Brian Tiger Chow committed
22 23 24 25
	}
}

type network struct {
26 27 28
	clients       map[peer.ID]bsnet.Receiver
	routingserver mockrouting.Server
	delay         delay.D
Brian Tiger Chow's avatar
Brian Tiger Chow committed
29 30
}

31
func (n *network) Adapter(p testutil.Identity) bsnet.BitSwapNetwork {
Brian Tiger Chow's avatar
Brian Tiger Chow committed
32
	client := &networkClient{
33
		local:   p.ID(),
34
		network: n,
Brian Tiger Chow's avatar
Brian Tiger Chow committed
35
		routing: n.routingserver.Client(p),
Brian Tiger Chow's avatar
Brian Tiger Chow committed
36
	}
37
	n.clients[p.ID()] = client
Brian Tiger Chow's avatar
Brian Tiger Chow committed
38 39 40
	return client
}

41 42
func (n *network) HasPeer(p peer.ID) bool {
	_, found := n.clients[p]
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
43 44 45
	return found
}

Brian Tiger Chow's avatar
Brian Tiger Chow committed
46 47 48 49
// TODO should this be completely asynchronous?
// TODO what does the network layer do with errors received from services?
func (n *network) SendMessage(
	ctx context.Context,
50 51
	from peer.ID,
	to peer.ID,
Brian Tiger Chow's avatar
Brian Tiger Chow committed
52 53
	message bsmsg.BitSwapMessage) error {

54
	receiver, ok := n.clients[to]
Brian Tiger Chow's avatar
Brian Tiger Chow committed
55 56 57 58 59 60 61 62 63 64 65 66 67
	if !ok {
		return errors.New("Cannot locate peer on network")
	}

	// nb: terminate the context since the context wouldn't actually be passed
	// over the network in a real scenario

	go n.deliver(receiver, from, message)

	return nil
}

func (n *network) deliver(
68 69
	r bsnet.Receiver, from peer.ID, message bsmsg.BitSwapMessage) error {
	if message == nil || from == "" {
Brian Tiger Chow's avatar
Brian Tiger Chow committed
70 71 72
		return errors.New("Invalid input")
	}

73 74
	n.delay.Wait()

75 76
	r.ReceiveMessage(context.TODO(), from, message)
	return nil
Brian Tiger Chow's avatar
Brian Tiger Chow committed
77 78 79
}

type networkClient struct {
80
	local peer.ID
Brian Tiger Chow's avatar
Brian Tiger Chow committed
81
	bsnet.Receiver
82
	network *network
83
	routing routing.IpfsRouting
Brian Tiger Chow's avatar
Brian Tiger Chow committed
84 85 86 87
}

func (nc *networkClient) SendMessage(
	ctx context.Context,
88
	to peer.ID,
Brian Tiger Chow's avatar
Brian Tiger Chow committed
89 90 91 92
	message bsmsg.BitSwapMessage) error {
	return nc.network.SendMessage(ctx, nc.local, to, message)
}

93
// FindProvidersAsync returns a channel of providers for the given key
94
func (nc *networkClient) FindProvidersAsync(ctx context.Context, k key.Key, max int) <-chan peer.ID {
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112

	// NB: this function duplicates the PeerInfo -> ID transformation in the
	// bitswap network adapter. Not to worry. This network client will be
	// deprecated once the ipfsnet.Mock is added. The code below is only
	// temporary.

	out := make(chan peer.ID)
	go func() {
		defer close(out)
		providers := nc.routing.FindProvidersAsync(ctx, k, max)
		for info := range providers {
			select {
			case <-ctx.Done():
			case out <- info.ID:
			}
		}
	}()
	return out
113 114 115
}

// Provide provides the key to the network
116
func (nc *networkClient) Provide(ctx context.Context, k key.Key) error {
117 118 119
	return nc.routing.Provide(ctx, k)
}

Brian Tiger Chow's avatar
Brian Tiger Chow committed
120 121 122
func (nc *networkClient) SetDelegate(r bsnet.Receiver) {
	nc.Receiver = r
}
123 124 125 126 127 128 129 130 131

func (nc *networkClient) ConnectTo(_ context.Context, p peer.ID) error {
	if !nc.network.HasPeer(p) {
		return errors.New("no such peer in network")
	}
	nc.network.clients[p].PeerConnected(nc.local)
	nc.Receiver.PeerConnected(p)
	return nil
}