/
kademlia.go
93 lines (74 loc) · 1.64 KB
/
kademlia.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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
87
88
89
90
91
92
93
package kademlia
import (
"encoding/hex"
"errors"
"fmt"
db "github.com/syndtr/goleveldb/leveldb"
"log"
"net"
"net/rpc"
"time"
)
const (
VALUES_DB_PATH = "db/values-"
)
type Kademlia struct {
routes *RoutingTable
valuesDB *db.DB
NetworkID string
}
func NewKademlia(self Contact, networkID string) *Kademlia {
ret := &Kademlia{
routes: NewRoutingTable(self),
valuesDB: nil,
NetworkID: networkID,
}
hexID := hex.EncodeToString(self.ID[:])
conn, err := db.OpenFile(VALUES_DB_PATH+hexID, nil)
if err != nil {
log.Println(err)
panic("Unable to open values database")
}
defer conn.Close()
ret.valuesDB = conn
return ret
}
// Generic RPC base
type RPCHeader struct {
Sender Contact
NetworkID string
}
// Every RPC updates routing tables in Kademlia
func (k *Kademlia) HandleRPC(request RPCHeader, response *RPCHeader) error {
if request.NetworkID != k.NetworkID {
return errors.New(fmt.Sprintf("Expected Network ID %s, go %s", k.NetworkID, request.NetworkID))
}
// Update routing table for all incoming RPCs
k.routes.Update(request.Sender)
// Pong with sender
response.Sender = k.routes.self
return nil
}
func dialContact(contact Contact) (*rpc.Client, error) {
connection, err := net.DialTimeout("tcp", contact.Address, 5*time.Second)
if err != nil {
return nil, err
}
return rpc.NewClient(connection), nil
}
func (k *Kademlia) Serve() error {
rpc.Register(&KademliaCore{k})
l, err := net.Listen("tcp", k.routes.self.Address)
if err != nil {
return err
}
go rpc.Accept(l)
return nil
}
/*
* KademliaCore
* Handles RPC interactions between client/server
*/
type KademliaCore struct {
kad *Kademlia
}