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

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
	peer      *peer.Peer
}

Jeromy's avatar
Jeromy committed
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 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
	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
}

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

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

func (mr *MockRouter) FindProvidersAsync(ctx context.Context, k u.Key, max int) <-chan *peer.Peer {
	out := make(chan *peer.Peer)
	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 {
	Announce(*peer.Peer, u.Key) error

	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 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 128 129 130 131 132
}

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

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

func (rs *hashTable) Announce(p *peer.Peer, k u.Key) error {
	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
}

func (rs *hashTable) Providers(k u.Key) []*peer.Peer {
	rs.lock.RLock()
	defer rs.lock.RUnlock()
	ret := make([]*peer.Peer, 0)
	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 135 136 137 138 139

func (rs *hashTable) Client(p *peer.Peer) routing.IpfsRouting {
	return &MockRouter{
		peer:      p,
		hashTable: rs,
	}
}