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