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

import (
	"errors"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
5
	"fmt"
Brian Tiger Chow's avatar
Brian Tiger Chow committed
6 7 8 9 10

	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
	bsmsg "github.com/jbenet/go-ipfs/exchange/bitswap/message"
	bsnet "github.com/jbenet/go-ipfs/exchange/bitswap/network"
	peer "github.com/jbenet/go-ipfs/peer"
11 12 13
	routing "github.com/jbenet/go-ipfs/routing"
	mockrouting "github.com/jbenet/go-ipfs/routing/mock"
	util "github.com/jbenet/go-ipfs/util"
14
	delay "github.com/jbenet/go-ipfs/util/delay"
15
	testutil "github.com/jbenet/go-ipfs/util/testutil"
Brian Tiger Chow's avatar
Brian Tiger Chow committed
16 17
)

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

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

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

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

Brian Tiger Chow's avatar
Brian Tiger Chow committed
47 48 49 50
// 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,
51 52
	from peer.ID,
	to peer.ID,
Brian Tiger Chow's avatar
Brian Tiger Chow committed
53 54
	message bsmsg.BitSwapMessage) error {

55
	receiver, ok := n.clients[to]
Brian Tiger Chow's avatar
Brian Tiger Chow committed
56 57 58 59 60 61 62 63 64 65 66 67 68
	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(
69 70
	r bsnet.Receiver, from peer.ID, message bsmsg.BitSwapMessage) error {
	if message == nil || from == "" {
Brian Tiger Chow's avatar
Brian Tiger Chow committed
71 72 73
		return errors.New("Invalid input")
	}

74 75
	n.delay.Wait()

76
	nextPeer, nextMsg := r.ReceiveMessage(context.TODO(), from, message)
Brian Tiger Chow's avatar
Brian Tiger Chow committed
77

78
	if (nextPeer == "" && nextMsg != nil) || (nextMsg == nil && nextPeer != "") {
Brian Tiger Chow's avatar
Brian Tiger Chow committed
79 80 81
		return errors.New("Malformed client request")
	}

82
	if nextPeer == "" && nextMsg == nil { // no response to send
Brian Tiger Chow's avatar
Brian Tiger Chow committed
83 84 85
		return nil
	}

86
	nextReceiver, ok := n.clients[nextPeer]
Brian Tiger Chow's avatar
Brian Tiger Chow committed
87 88 89 90 91 92 93 94 95 96
	if !ok {
		return errors.New("Cannot locate peer on network")
	}
	go n.deliver(nextReceiver, nextPeer, nextMsg)
	return nil
}

// TODO
func (n *network) SendRequest(
	ctx context.Context,
97 98
	from peer.ID,
	to peer.ID,
Brian Tiger Chow's avatar
Brian Tiger Chow committed
99 100 101
	message bsmsg.BitSwapMessage) (
	incoming bsmsg.BitSwapMessage, err error) {

102
	r, ok := n.clients[to]
Brian Tiger Chow's avatar
Brian Tiger Chow committed
103 104 105
	if !ok {
		return nil, errors.New("Cannot locate peer on network")
	}
106
	nextPeer, nextMsg := r.ReceiveMessage(context.TODO(), from, message)
Brian Tiger Chow's avatar
Brian Tiger Chow committed
107 108

	// TODO dedupe code
109
	if (nextPeer == "" && nextMsg != nil) || (nextMsg == nil && nextPeer != "") {
110 111
		r.ReceiveError(errors.New("Malformed client request"))
		return nil, nil
Brian Tiger Chow's avatar
Brian Tiger Chow committed
112 113 114
	}

	// TODO dedupe code
115
	if nextPeer == "" && nextMsg == nil {
Brian Tiger Chow's avatar
Brian Tiger Chow committed
116 117 118 119
		return nil, nil
	}

	// TODO test when receiver doesn't immediately respond to the initiator of the request
120
	if nextPeer != from {
Brian Tiger Chow's avatar
Brian Tiger Chow committed
121
		go func() {
122
			nextReceiver, ok := n.clients[nextPeer]
Brian Tiger Chow's avatar
Brian Tiger Chow committed
123 124 125 126 127
			if !ok {
				// TODO log the error?
			}
			n.deliver(nextReceiver, nextPeer, nextMsg)
		}()
128
		return nil, nil
Brian Tiger Chow's avatar
Brian Tiger Chow committed
129 130 131 132 133
	}
	return nextMsg, nil
}

type networkClient struct {
134
	local peer.ID
Brian Tiger Chow's avatar
Brian Tiger Chow committed
135
	bsnet.Receiver
136
	network *network
137
	routing routing.IpfsRouting
Brian Tiger Chow's avatar
Brian Tiger Chow committed
138 139 140 141
}

func (nc *networkClient) SendMessage(
	ctx context.Context,
142
	to peer.ID,
Brian Tiger Chow's avatar
Brian Tiger Chow committed
143 144 145 146 147 148
	message bsmsg.BitSwapMessage) error {
	return nc.network.SendMessage(ctx, nc.local, to, message)
}

func (nc *networkClient) SendRequest(
	ctx context.Context,
149
	to peer.ID,
Brian Tiger Chow's avatar
Brian Tiger Chow committed
150 151 152 153
	message bsmsg.BitSwapMessage) (incoming bsmsg.BitSwapMessage, err error) {
	return nc.network.SendRequest(ctx, nc.local, to, message)
}

154
// FindProvidersAsync returns a channel of providers for the given key
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
func (nc *networkClient) FindProvidersAsync(ctx context.Context, k util.Key, max int) <-chan peer.ID {

	// 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
174 175 176 177 178 179 180
}

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

181
func (nc *networkClient) DialPeer(ctx context.Context, p peer.ID) error {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
182
	// no need to do anything because dialing isn't a thing in this test net.
183 184
	if !nc.network.HasPeer(p) {
		return fmt.Errorf("Peer not in network: %s", p)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
185 186 187 188
	}
	return nil
}

Brian Tiger Chow's avatar
Brian Tiger Chow committed
189 190 191
func (nc *networkClient) SetDelegate(r bsnet.Receiver) {
	nc.Receiver = r
}