@cryptotaxi247 / kubo / commits / 3444d41dc

work on framework for dht message handling

Jeromy committed Jul 29, 2014 at 19:33 UTC 3444d41dce89a9c1b94785509d93b44be8c837dc
7 files changed +102 -40
routing/dht/dht.go
+39 -17
@@ -2,6 +2,8 @@ package dht
2
3 import (
4 swarm "github.com/jbenet/go-ipfs/swarm"
5 + u "github.com/jbenet/go-ipfs/util"
6 + "code.google.com/p/goprotobuf/proto"
7 "sync"
8 )
9
@@ -14,36 +16,56 @@ type IpfsDHT struct {
16
17 network *swarm.Swarm
18
17 - listeners map[uint64]chan swarm.Message
19 + // map of channels waiting for reply messages
20 + listeners map[uint64]chan *swarm.Message
21 listenLock sync.RWMutex
22 +
23 + // Signal to shutdown dht
24 + shutdown chan struct{}
25 }
26
27 // Read in all messages from swarm and handle them appropriately
28 // NOTE: this function is just a quick sketch
29 func (dht *IpfsDHT) handleMessages() {
24 - for mes := range dht.network.Chan.Incoming {
25 - for {
26 - select {
27 - case mes := <-dht.network.Chan.Incoming:
28 - // Unmarshal message
29 - dht.listenLock.RLock()
30 - ch, ok := dht.listeners[id]
31 - dht.listenLock.RUnlock()
32 - if ok {
33 - // Send message to waiting goroutine
34 - ch <- mes
35 - }
36 -
37 - //case closeChan: or something
30 + for {
31 + select {
32 + case mes := <-dht.network.Chan.Incoming:
33 + pmes := new(DHTMessage)
34 + err := proto.Unmarshal(mes.Data, pmes)
35 + if err != nil {
36 + u.PErr("Failed to decode protobuf message: %s", err)
37 + continue
38 + }
39 +
40 + // Note: not sure if this is the correct place for this
41 + dht.listenLock.RLock()
42 + ch, ok := dht.listeners[pmes.GetId()]
43 + dht.listenLock.RUnlock()
44 + if ok {
45 + ch <- mes
46 }
47 + //
48 +
49 + // Do something else with the messages?
50 + switch pmes.GetType() {
51 + case DHTMessage_ADD_PROVIDER:
52 + case DHTMessage_FIND_NODE:
53 + case DHTMessage_GET_PROVIDERS:
54 + case DHTMessage_GET_VALUE:
55 + case DHTMessage_PING:
56 + case DHTMessage_PUT_VALUE:
57 + }
58 +
59 + case <-dht.shutdown:
60 + return
61 }
62 }
63 }
64
65 // Register a handler for a specific message ID, used for getting replies
66 // to certain messages (i.e. response to a GET_VALUE message)
45 -func (dht *IpfsDHT) ListenFor(mesid uint64) <-chan swarm.Message {
46 - lchan := make(chan swarm.Message)
67 +func (dht *IpfsDHT) ListenFor(mesid uint64) <-chan *swarm.Message {
68 + lchan := make(chan *swarm.Message)
69 dht.listenLock.Lock()
70 dht.listeners[mesid] = lchan
71 dht.listenLock.Unlock()
routing/dht/messages.pb.go
+24 -10
@@ -23,23 +23,29 @@ var _ = math.Inf
23 type DHTMessage_MessageType int32
24
25 const (
26 - DHTMessage_PUT_VALUE DHTMessage_MessageType = 0
27 - DHTMessage_GET_VALUE DHTMessage_MessageType = 1
28 - DHTMessage_PING DHTMessage_MessageType = 2
29 - DHTMessage_FIND_NODE DHTMessage_MessageType = 3
26 + DHTMessage_PUT_VALUE DHTMessage_MessageType = 0
27 + DHTMessage_GET_VALUE DHTMessage_MessageType = 1
28 + DHTMessage_ADD_PROVIDER DHTMessage_MessageType = 2
29 + DHTMessage_GET_PROVIDERS DHTMessage_MessageType = 3
30 + DHTMessage_FIND_NODE DHTMessage_MessageType = 4
31 + DHTMessage_PING DHTMessage_MessageType = 5
32 )
33
34 var DHTMessage_MessageType_name = map[int32]string{
35 0: "PUT_VALUE",
36 1: "GET_VALUE",
35 - 2: "PING",
36 - 3: "FIND_NODE",
37 + 2: "ADD_PROVIDER",
38 + 3: "GET_PROVIDERS",
39 + 4: "FIND_NODE",
40 + 5: "PING",
41 }
42 var DHTMessage_MessageType_value = map[string]int32{
39 - "PUT_VALUE": 0,
40 - "GET_VALUE": 1,
41 - "PING": 2,
42 - "FIND_NODE": 3,
43 + "PUT_VALUE": 0,
44 + "GET_VALUE": 1,
45 + "ADD_PROVIDER": 2,
46 + "GET_PROVIDERS": 3,
47 + "FIND_NODE": 4,
48 + "PING": 5,
49 }
50
51 func (x DHTMessage_MessageType) Enum() *DHTMessage_MessageType {
@@ -63,6 +69,7 @@ type DHTMessage struct {
69 Type *DHTMessage_MessageType `protobuf:"varint,1,req,name=type,enum=dht.DHTMessage_MessageType" json:"type,omitempty"`
70 Key *string `protobuf:"bytes,2,opt,name=key" json:"key,omitempty"`
71 Value []byte `protobuf:"bytes,3,opt,name=value" json:"value,omitempty"`
72 + Id *uint64 `protobuf:"varint,4,req,name=id" json:"id,omitempty"`
73 XXX_unrecognized []byte `json:"-"`
74 }
75
@@ -91,6 +98,13 @@ func (m *DHTMessage) GetValue() []byte {
98 return nil
99 }
100
101 +func (m *DHTMessage) GetId() uint64 {
102 + if m != nil && m.Id != nil {
103 + return *m.Id
104 + }
105 + return 0
106 +}
107 +
108 func init() {
109 proto.RegisterEnum("dht.DHTMessage_MessageType", DHTMessage_MessageType_name, DHTMessage_MessageType_value)
110 }
routing/dht/messages.proto
+1 -1
@@ -15,5 +15,5 @@ message DHTMessage {
15 required MessageType type = 1;
16 optional string key = 2;
17 optional bytes value = 3;
18 - required int64 id = 4;
18 + required uint64 id = 4;
19 }
routing/dht/routing.go
+22 -7
@@ -7,6 +7,11 @@ import (
7 "time"
8 )
9
10 +// TODO: determine a way of creating and managing message IDs
11 +func GenerateMessageID() uint64 {
12 + return 4
13 +}
14 +
15 // This file implements the Routing interface for the IpfsDHT struct.
16
17 // Basic Put/Get
@@ -16,9 +21,15 @@ func (s *IpfsDHT) PutValue(key u.Key, value []byte) error {
21 var p *peer.Peer
22 p = s.routes.NearestNode(key)
23
19 - pmes := new(PutValue)
20 - pmes.Key = &key
24 + pmes_type := DHTMessage_PUT_VALUE
25 + str_key := string(key)
26 + mes_id := GenerateMessageID()
27 +
28 + pmes := new(DHTMessage)
29 + pmes.Type = &pmes_type
30 + pmes.Key = &str_key
31 pmes.Value = value
32 + pmes.Id = &mes_id
33
34 mes := new(swarm.Message)
35 mes.Data = []byte(pmes.String())
@@ -33,23 +44,27 @@ func (s *IpfsDHT) GetValue(key u.Key, timeout time.Duration) ([]byte, error) {
44 var p *peer.Peer
45 p = s.routes.NearestNode(key)
46
47 + str_key := string(key)
48 + mes_type := DHTMessage_GET_VALUE
49 + mes_id := GenerateMessageID()
50 // protobuf structure
37 - pmes := new(GetValue)
38 - pmes.Key = &key
39 - pmes.Id = GenerateMessageID()
51 + pmes := new(DHTMessage)
52 + pmes.Type = &mes_type
53 + pmes.Key = &str_key
54 + pmes.Id = &mes_id
55
56 mes := new(swarm.Message)
57 mes.Data = []byte(pmes.String())
58 mes.Peer = p
59
45 - response_chan := s.ListenFor(pmes.Id)
60 + response_chan := s.ListenFor(*pmes.Id)
61
62 // Wait for either the response or a timeout
63 timeup := time.After(timeout)
64 select {
65 case <-timeup:
66 // TODO: unregister listener
52 - return nil, timeoutError
67 + return nil, u.ErrTimeout
68 case resp := <-response_chan:
69 return resp.Data, nil
70 }
routing/dht/table.go
+8
@@ -3,6 +3,9 @@ package dht
3 import (
4 "bytes"
5 "container/list"
6 +
7 + peer "github.com/jbenet/go-ipfs/peer"
8 + u "github.com/jbenet/go-ipfs/util"
9 )
10
11 // ID for IpfsDHT should be a byte slice, to allow for simpler operations
@@ -22,6 +25,11 @@ type RoutingTable struct {
25 Buckets []Bucket
26 }
27
28 +//TODO: make this accept an ID, requires method of converting keys to IDs
29 +func (rt *RoutingTable) NearestNode(key u.Key) *peer.Peer {
30 + panic("Function not implemented.")
31 +}
32 +
33 func (id ID) Equal(other ID) bool {
34 return bytes.Equal(id, other)
35 }
swarm/swarm.go
+5 -5
@@ -21,8 +21,8 @@ type Message struct {
21
22 // Chan is a swam channel, which provides duplex communication and errors.
23 type Chan struct {
24 - Outgoing chan Message
25 - Incoming chan Message
24 + Outgoing chan *Message
25 + Incoming chan *Message
26 Errors chan error
27 Close chan bool
28 }
@@ -30,8 +30,8 @@ type Chan struct {
30 // NewChan constructs a Chan instance, with given buffer size bufsize.
31 func NewChan(bufsize int) *Chan {
32 return &Chan{
33 - Outgoing: make(chan Message, bufsize),
34 - Incoming: make(chan Message, bufsize),
33 + Outgoing: make(chan *Message, bufsize),
34 + Incoming: make(chan *Message, bufsize),
35 Errors: make(chan error),
36 Close: make(chan bool, bufsize),
37 }
@@ -197,7 +197,7 @@ Loop:
197 }
198
199 // wrap it for consumers.
200 - msg := Message{Peer: conn.Peer, Data: data}
200 + msg := &Message{Peer: conn.Peer, Data: data}
201 s.Chan.Incoming <- msg
202 }
203 }
util/util.go
+3
@@ -14,6 +14,9 @@ var Debug bool
14 // ErrNotImplemented signifies a function has not been implemented yet.
15 var ErrNotImplemented = fmt.Errorf("Error: not implemented yet.")
16
17 +// ErrTimeout implies that a timeout has been triggered
18 +var ErrTimeout = fmt.Errorf("Error: Call timed out.")
19 +
20 // Key is a string representation of multihash for use with maps.
21 type Key string
22