You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

183 lines
3.6 KiB

  1. package node
  2. import (
  3. "encoding/hex"
  4. "fmt"
  5. "go-dht/config"
  6. "go-dht/kademlia"
  7. "io/ioutil"
  8. "net"
  9. "net/http"
  10. "net/rpc"
  11. "time"
  12. log "github.com/sirupsen/logrus"
  13. )
  14. type Node struct {
  15. port string
  16. kademlia *kademlia.Kademlia
  17. }
  18. func NewNode() (Node, error) {
  19. id, err := kademlia.NewID()
  20. if err != nil {
  21. return Node{}, err
  22. }
  23. var n Node
  24. n.kademlia = kademlia.NewKademliaTable(id, config.C.Addr, config.C.Port)
  25. return n, nil
  26. }
  27. func LoadNode(idStr string) (Node, error) {
  28. id, err := kademlia.IDFromString(idStr)
  29. if err != nil {
  30. return Node{}, err
  31. }
  32. var n Node
  33. n.kademlia = kademlia.NewKademliaTable(id, config.C.Addr, config.C.Port)
  34. return n, nil
  35. }
  36. func (n Node) ID() kademlia.ID {
  37. return n.kademlia.N.ID
  38. }
  39. func (n Node) Kademlia() kademlia.Kademlia {
  40. return *n.kademlia
  41. }
  42. func (n *Node) Start() error {
  43. // rpc server
  44. err := rpc.Register(n)
  45. if err != nil {
  46. return err
  47. }
  48. rpc.HandleHTTP()
  49. listener, err := net.Listen("tcp", ":"+config.C.Port)
  50. if err != nil {
  51. return err
  52. }
  53. go func() {
  54. // TMP in order to print the KBuckets of the node
  55. for {
  56. fmt.Println(n.kademlia)
  57. time.Sleep(8 * time.Second)
  58. }
  59. }()
  60. go n.pingKnownNodes(config.C.KnownNodes)
  61. go n.kademlia.Update(kademlia.ListedNode{
  62. ID: n.ID(),
  63. Addr: config.C.Addr,
  64. Port: config.C.Port,
  65. })
  66. err = http.Serve(listener, nil)
  67. if err != nil {
  68. return err
  69. }
  70. return nil
  71. }
  72. func (n *Node) pingKnownNodes(lns []kademlia.ListedNode) error {
  73. for _, ln := range lns {
  74. err := n.kademlia.CallPing(ln)
  75. if err != nil {
  76. log.Warning("[pingKnownNodes]", err)
  77. }
  78. }
  79. return nil
  80. }
  81. // Exposed RPC calls: Ping, Store, FindNode, FindValue
  82. func (n *Node) Ping(ln kademlia.ListedNode, thisLn *kademlia.ListedNode) error {
  83. log.Info("[rpc] PING from ", ln.ID)
  84. n.kademlia.Update(ln)
  85. *thisLn = kademlia.ListedNode{
  86. ID: n.ID(),
  87. Addr: config.C.Addr,
  88. Port: config.C.Port,
  89. }
  90. // perform PONG call to the requester (maybe ping&pong can be unified)
  91. err := n.kademlia.CallPong(ln)
  92. if err != nil {
  93. log.Warning("[PONG]", err)
  94. }
  95. return nil
  96. }
  97. func (n *Node) Pong(ln kademlia.ListedNode, ack *bool) error {
  98. log.Info("[rpc] PONG")
  99. n.kademlia.Update(ln)
  100. return nil
  101. }
  102. func (n *Node) Store(data []byte, ack *bool) error {
  103. log.Info("[rpc] STORE")
  104. h := kademlia.HashData(data)
  105. if n.kademlia.KBucket(h) != 0 {
  106. *ack = false
  107. log.Warning("[STORE] data not for this node")
  108. return nil
  109. }
  110. err := ioutil.WriteFile(config.C.Storage+"/"+hex.EncodeToString(h[:]), data, 0644)
  111. if err != nil {
  112. *ack = false
  113. log.Warning("[STORE]", err)
  114. return err
  115. }
  116. *ack = true
  117. return nil
  118. }
  119. func (n *Node) FindNode(id kademlia.ID, lns *[]kademlia.ListedNode) error {
  120. log.Info("[rpc] FIND_NODE")
  121. // k := n.kademlia.KBucket(ln.ID)
  122. k, err := n.kademlia.GetClosestKBucket(id)
  123. if err != nil {
  124. log.Debug("[rpc] FIND_NODE ERROR: ", err)
  125. *lns = []kademlia.ListedNode{}
  126. return nil
  127. }
  128. log.Info("[FIND_NODE] k", k)
  129. bucket := n.kademlia.KBuckets[k]
  130. *lns = bucket
  131. return nil
  132. }
  133. type FindValueResp struct {
  134. Value []byte
  135. Lns []kademlia.ListedNode
  136. }
  137. func (n *Node) FindValue(id kademlia.ID, resp *FindValueResp) error {
  138. log.Info("[rpc] FIND_VALUE")
  139. // first check if value is in this node storage
  140. f, err := ioutil.ReadFile(config.C.Storage + "/" + id.String())
  141. if err == nil {
  142. // value exists, return it
  143. *resp = FindValueResp{
  144. Value: f,
  145. }
  146. return nil
  147. }
  148. // k := n.kademlia.KBucket(id)
  149. k, err := n.kademlia.GetClosestKBucket(id)
  150. if err != nil {
  151. *resp = FindValueResp{}
  152. return nil
  153. }
  154. log.Info("[FIND_VALUE] k", k)
  155. // bucket := n.kademlia.KBuckets[k]
  156. *resp = FindValueResp{
  157. Lns: n.kademlia.KBuckets[k],
  158. }
  159. return nil
  160. }