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

import (
4
	"context"
Brian Tiger Chow's avatar
Brian Tiger Chow committed
5
	"errors"
Steven Allen's avatar
Steven Allen committed
6
	"sync"
Brian Tiger Chow's avatar
Brian Tiger Chow committed
7

8 9 10 11
	bsmsg "github.com/ipfs/go-ipfs/exchange/bitswap/message"
	bsnet "github.com/ipfs/go-ipfs/exchange/bitswap/network"
	mockrouting "github.com/ipfs/go-ipfs/routing/mock"
	delay "github.com/ipfs/go-ipfs/thirdparty/delay"
12

Steven Allen's avatar
Steven Allen committed
13
	routing "gx/ipfs/QmRijoA6zGS98ELTDbGsLWPZbVotYsGbjp3RbXcKCYBeon/go-libp2p-routing"
14
	logging "gx/ipfs/QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52/go-log"
Steven Allen's avatar
Steven Allen committed
15 16 17 18
	ifconnmgr "gx/ipfs/QmZdqgq4h6AdodSmPwb5FZzhwnmhchu1hhJgv8tnFdod1o/go-libp2p-interface-connmgr"
	peer "gx/ipfs/Qma7H6RW8wRrfZpNSXwxYGcd1E149s42FpWNpDNieSVrnU/go-libp2p-peer"
	cid "gx/ipfs/QmcZfnkapfECQGcLZaf9B79NRg7cRa9EnZh4LSbkCzwNvY/go-cid"
	testutil "gx/ipfs/QmfB65MYJqaKzBiMvW47fquCRhmEeXW6AhrJSGM7TeY5eG/go-testutil"
Brian Tiger Chow's avatar
Brian Tiger Chow committed
19 20
)

21 22
var log = logging.Logger("bstestnet")

23
func VirtualNetwork(rs mockrouting.Server, d delay.D) Network {
Brian Tiger Chow's avatar
Brian Tiger Chow committed
24
	return &network{
25 26
		clients:       make(map[peer.ID]bsnet.Receiver),
		delay:         d,
27
		routingserver: rs,
28
		conns:         make(map[string]struct{}),
Brian Tiger Chow's avatar
Brian Tiger Chow committed
29 30 31 32
	}
}

type network struct {
Steven Allen's avatar
Steven Allen committed
33
	mu            sync.Mutex
34 35 36
	clients       map[peer.ID]bsnet.Receiver
	routingserver mockrouting.Server
	delay         delay.D
37
	conns         map[string]struct{}
Brian Tiger Chow's avatar
Brian Tiger Chow committed
38 39
}

40
func (n *network) Adapter(p testutil.Identity) bsnet.BitSwapNetwork {
Steven Allen's avatar
Steven Allen committed
41 42 43
	n.mu.Lock()
	defer n.mu.Unlock()

Brian Tiger Chow's avatar
Brian Tiger Chow committed
44
	client := &networkClient{
45
		local:   p.ID(),
46
		network: n,
Brian Tiger Chow's avatar
Brian Tiger Chow committed
47
		routing: n.routingserver.Client(p),
Brian Tiger Chow's avatar
Brian Tiger Chow committed
48
	}
49
	n.clients[p.ID()] = client
Brian Tiger Chow's avatar
Brian Tiger Chow committed
50 51 52
	return client
}

53
func (n *network) HasPeer(p peer.ID) bool {
Steven Allen's avatar
Steven Allen committed
54 55 56
	n.mu.Lock()
	defer n.mu.Unlock()

57
	_, found := n.clients[p]
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
58 59 60
	return found
}

Brian Tiger Chow's avatar
Brian Tiger Chow committed
61 62 63 64
// 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,
65 66
	from peer.ID,
	to peer.ID,
Brian Tiger Chow's avatar
Brian Tiger Chow committed
67 68
	message bsmsg.BitSwapMessage) error {

Steven Allen's avatar
Steven Allen committed
69 70 71
	n.mu.Lock()
	defer n.mu.Unlock()

72
	receiver, ok := n.clients[to]
Brian Tiger Chow's avatar
Brian Tiger Chow committed
73 74 75 76 77 78 79 80 81 82 83 84 85
	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(
86 87
	r bsnet.Receiver, from peer.ID, message bsmsg.BitSwapMessage) error {
	if message == nil || from == "" {
Brian Tiger Chow's avatar
Brian Tiger Chow committed
88 89 90
		return errors.New("Invalid input")
	}

91 92
	n.delay.Wait()

93 94
	r.ReceiveMessage(context.TODO(), from, message)
	return nil
Brian Tiger Chow's avatar
Brian Tiger Chow committed
95 96 97
}

type networkClient struct {
98
	local peer.ID
Brian Tiger Chow's avatar
Brian Tiger Chow committed
99
	bsnet.Receiver
100
	network *network
101
	routing routing.IpfsRouting
Brian Tiger Chow's avatar
Brian Tiger Chow committed
102 103 104 105
}

func (nc *networkClient) SendMessage(
	ctx context.Context,
106
	to peer.ID,
Brian Tiger Chow's avatar
Brian Tiger Chow committed
107 108 109 110
	message bsmsg.BitSwapMessage) error {
	return nc.network.SendMessage(ctx, nc.local, to, message)
}

111
// FindProvidersAsync returns a channel of providers for the given key
112
func (nc *networkClient) FindProvidersAsync(ctx context.Context, k *cid.Cid, max int) <-chan peer.ID {
113 114 115 116 117 118 119 120 121

	// 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)
122
		providers := nc.routing.FindProvidersAsync(ctx, k, max)
123 124 125 126 127 128 129 130
		for info := range providers {
			select {
			case <-ctx.Done():
			case out <- info.ID:
			}
		}
	}()
	return out
131 132
}

133 134 135 136
func (nc *networkClient) ConnectionManager() ifconnmgr.ConnManager {
	return &ifconnmgr.NullConnMgr{}
}

Jeromy's avatar
Jeromy committed
137 138 139 140 141 142 143
type messagePasser struct {
	net    *network
	target peer.ID
	local  peer.ID
	ctx    context.Context
}

144 145
func (mp *messagePasser) SendMsg(ctx context.Context, m bsmsg.BitSwapMessage) error {
	return mp.net.SendMessage(ctx, mp.local, mp.target, m)
Jeromy's avatar
Jeromy committed
146 147 148 149 150 151
}

func (mp *messagePasser) Close() error {
	return nil
}

152 153 154 155
func (mp *messagePasser) Reset() error {
	return nil
}

Jeromy's avatar
Jeromy committed
156 157 158 159 160 161 162 163 164
func (n *networkClient) NewMessageSender(ctx context.Context, p peer.ID) (bsnet.MessageSender, error) {
	return &messagePasser{
		net:    n.network,
		target: p,
		local:  n.local,
		ctx:    ctx,
	}, nil
}

165
// Provide provides the key to the network
166
func (nc *networkClient) Provide(ctx context.Context, k *cid.Cid) error {
167
	return nc.routing.Provide(ctx, k, true)
168 169
}

Brian Tiger Chow's avatar
Brian Tiger Chow committed
170 171 172
func (nc *networkClient) SetDelegate(r bsnet.Receiver) {
	nc.Receiver = r
}
173 174

func (nc *networkClient) ConnectTo(_ context.Context, p peer.ID) error {
Steven Allen's avatar
Steven Allen committed
175 176 177 178 179
	nc.network.mu.Lock()

	otherClient, ok := nc.network.clients[p]
	if !ok {
		nc.network.mu.Unlock()
180 181
		return errors.New("no such peer in network")
	}
Steven Allen's avatar
Steven Allen committed
182

183 184
	tag := tagForPeers(nc.local, p)
	if _, ok := nc.network.conns[tag]; ok {
Steven Allen's avatar
Steven Allen committed
185
		nc.network.mu.Unlock()
186 187 188 189
		log.Warning("ALREADY CONNECTED TO PEER (is this a reconnect? test lib needs fixing)")
		return nil
	}
	nc.network.conns[tag] = struct{}{}
Steven Allen's avatar
Steven Allen committed
190 191
	nc.network.mu.Unlock()

192 193
	// TODO: add handling for disconnects

Steven Allen's avatar
Steven Allen committed
194
	otherClient.PeerConnected(nc.local)
195 196 197
	nc.Receiver.PeerConnected(p)
	return nil
}
198 199 200 201 202 203 204

func tagForPeers(a, b peer.ID) string {
	if a < b {
		return string(a + b)
	}
	return string(b + a)
}