routing.go 2.78 KB
Newer Older
1
package mock
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

import (
	"errors"
	"math/rand"
	"sync"

	"github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
	ds "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/datastore.go"
	peer "github.com/jbenet/go-ipfs/peer"
	routing "github.com/jbenet/go-ipfs/routing"
	u "github.com/jbenet/go-ipfs/util"
)

var _ routing.IpfsRouting = &MockRouter{}

type MockRouter struct {
	datastore ds.Datastore
	hashTable RoutingServer
20
	peer      peer.Peer
21 22
}

23
func NewMockRouter(local peer.Peer, dstore ds.Datastore) routing.IpfsRouting {
24 25 26 27 28 29 30 31 32 33 34 35
	return &MockRouter{
		datastore: dstore,
		peer:      local,
		hashTable: VirtualRoutingServer(),
	}
}

func (mr *MockRouter) SetRoutingServer(rs RoutingServer) {
	mr.hashTable = rs
}

func (mr *MockRouter) PutValue(ctx context.Context, key u.Key, val []byte) error {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
36
	return mr.datastore.Put(key.DsKey(), val)
37 38 39
}

func (mr *MockRouter) GetValue(ctx context.Context, key u.Key) ([]byte, error) {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
40
	v, err := mr.datastore.Get(key.DsKey())
41 42 43 44 45 46 47 48 49 50 51 52
	if err != nil {
		return nil, err
	}

	data, ok := v.([]byte)
	if !ok {
		return nil, errors.New("could not cast value from datastore")
	}

	return data, nil
}

53
func (mr *MockRouter) FindProviders(ctx context.Context, key u.Key) ([]peer.Peer, error) {
54 55 56
	return nil, nil
}

57
func (mr *MockRouter) FindPeer(ctx context.Context, pid peer.ID) (peer.Peer, error) {
58 59 60
	return nil, nil
}

61 62
func (mr *MockRouter) FindProvidersAsync(ctx context.Context, k u.Key, max int) <-chan peer.Peer {
	out := make(chan peer.Peer)
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
	go func() {
		defer close(out)
		for i, p := range mr.hashTable.Providers(k) {
			if max <= i {
				return
			}
			select {
			case out <- p:
			case <-ctx.Done():
				return
			}
		}
	}()
	return out
}

func (mr *MockRouter) Provide(_ context.Context, key u.Key) error {
	return mr.hashTable.Announce(mr.peer, key)
}

type RoutingServer interface {
84
	Announce(peer.Peer, u.Key) error
85

86
	Providers(u.Key) []peer.Peer
Jeromy's avatar
Jeromy committed
87

88
	Client(p peer.Peer) routing.IpfsRouting
89 90 91 92 93 94 95 96 97 98 99 100 101
}

func VirtualRoutingServer() RoutingServer {
	return &hashTable{
		providers: make(map[u.Key]peer.Map),
	}
}

type hashTable struct {
	lock      sync.RWMutex
	providers map[u.Key]peer.Map
}

102
func (rs *hashTable) Announce(p peer.Peer, k u.Key) error {
103 104 105 106 107 108 109 110 111 112 113
	rs.lock.Lock()
	defer rs.lock.Unlock()

	_, ok := rs.providers[k]
	if !ok {
		rs.providers[k] = make(peer.Map)
	}
	rs.providers[k][p.Key()] = p
	return nil
}

114
func (rs *hashTable) Providers(k u.Key) []peer.Peer {
115 116
	rs.lock.RLock()
	defer rs.lock.RUnlock()
117
	ret := make([]peer.Peer, 0)
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
	peerset, ok := rs.providers[k]
	if !ok {
		return ret
	}
	for _, peer := range peerset {
		ret = append(ret, peer)
	}

	for i := range ret {
		j := rand.Intn(i + 1)
		ret[i], ret[j] = ret[j], ret[i]
	}

	return ret
}
Jeromy's avatar
Jeromy committed
133

134
func (rs *hashTable) Client(p peer.Peer) routing.IpfsRouting {
Jeromy's avatar
Jeromy committed
135 136 137 138 139
	return &MockRouter{
		peer:      p,
		hashTable: rs,
	}
}