github.com/annchain/OG@v0.0.9/plugin/community/manager.go (about) 1 package community 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "github.com/annchain/OG/ffchan" 8 "github.com/libp2p/go-libp2p" 9 core "github.com/libp2p/go-libp2p-core/crypto" 10 "github.com/libp2p/go-libp2p-core/host" 11 "github.com/libp2p/go-libp2p-core/network" 12 "github.com/libp2p/go-libp2p-core/peer" 13 "github.com/libp2p/go-libp2p-core/peerstore" 14 swarm "github.com/libp2p/go-libp2p-swarm" 15 "github.com/multiformats/go-multiaddr" 16 "github.com/sirupsen/logrus" 17 "github.com/tinylib/msgp/msgp" 18 "log" 19 "math/rand" 20 "sync" 21 "time" 22 ) 23 24 var BackoffConnect = time.Second * 5 25 var IpLayerProtocol = "tcp" 26 27 type IoEvent struct { 28 Neighbour *Neighbour 29 Err error 30 } 31 32 type Neighbour struct { 33 Id peer.ID 34 Stream network.Stream 35 IoEventChannel chan *IoEvent 36 IncomingChannel chan *WireMessage 37 msgpReader *msgp.Reader 38 msgpWriter *msgp.Writer 39 event chan bool 40 outgoingChannel chan *Msg 41 quit chan bool 42 } 43 44 func (c *Neighbour) InitDefault() { 45 c.event = make(chan bool) 46 c.quit = make(chan bool) 47 c.outgoingChannel = make(chan *Msg) // messages already dispatched 48 } 49 50 func (c *Neighbour) StartRead() { 51 var err error 52 c.msgpReader = msgp.NewReader(c.Stream) 53 for { 54 msg := &WireMessage{} 55 err = msg.DecodeMsg(c.msgpReader) 56 if err != nil { 57 // bad message, drop 58 logrus.WithError(err).Warn("read error") 59 break 60 } 61 62 <-ffchan.NewTimeoutSenderShort(c.IncomingChannel, msg, "read").C 63 //c.IncomingChannel <- msg 64 } 65 // neighbour disconnected, notify the communicator 66 c.IoEventChannel <- &IoEvent{ 67 Neighbour: c, 68 Err: err, 69 } 70 71 } 72 73 func (c *Neighbour) StartWrite() { 74 var err error 75 c.msgpWriter = msgp.NewWriter(c.Stream) 76 loop: 77 for { 78 select { 79 case req := <-c.outgoingChannel: 80 logrus.Trace("neighbour got send request") 81 contentBytes, err := req.Content.MarshalMsg([]byte{}) 82 if err != nil { 83 panic(err) 84 } 85 86 wireMessage := WireMessage{ 87 MsgType: int(req.Typev), 88 ContentBytes: contentBytes, 89 SenderId: req.SenderId, 90 Signature: req.Sig, 91 } 92 93 err = wireMessage.EncodeMsg(c.msgpWriter) 94 if err != nil { 95 break 96 } 97 err = c.msgpWriter.Flush() 98 if err != nil { 99 break 100 } 101 logrus.Trace("neighbour sent") 102 103 case <-c.quit: 104 break loop 105 } 106 } 107 // neighbour disconnected, notify the communicator 108 c.IoEventChannel <- &IoEvent{ 109 Neighbour: c, 110 Err: err, 111 } 112 } 113 114 func (c *Neighbour) Send(req *Msg) { 115 <-ffchan.NewTimeoutSenderShort(c.outgoingChannel, req, "send").C 116 //c.outgoingChannel <- req 117 } 118 119 // LibP2pPhysicalCommunicator 120 type LibP2pPhysicalCommunicator struct { 121 Port int // listening port 122 PrivateKey core.PrivKey 123 124 node host.Host // p2p host to receive new streams 125 activePeers map[peer.ID]*Neighbour // active peers that will be reconnect if error 126 tryingPeers map[peer.ID]bool // peers that is trying to connect. 127 incomingChannel chan *WireMessage // incoming message channel 128 outgoingChannel chan *OutgoingRequest // universal outgoing channel to collect send requests 129 ioEventChannel chan *IoEvent // receive event when peer disconnects 130 131 initWait sync.WaitGroup 132 quit chan bool 133 mu sync.RWMutex 134 } 135 136 func (c *LibP2pPhysicalCommunicator) InitDefault() { 137 c.activePeers = make(map[peer.ID]*Neighbour) 138 c.tryingPeers = make(map[peer.ID]bool) 139 c.outgoingChannel = make(chan *OutgoingRequest) 140 c.incomingChannel = make(chan *WireMessage) 141 c.ioEventChannel = make(chan *IoEvent) 142 c.initWait.Add(1) 143 c.quit = make(chan bool) 144 } 145 146 func (c *LibP2pPhysicalCommunicator) Start() { 147 // start consuming queue 148 go c.Listen() 149 go c.consumeQueue() 150 go c.recoverPeer() 151 } 152 153 func (c *LibP2pPhysicalCommunicator) consumeQueue() { 154 c.initWait.Wait() 155 for { 156 select { 157 case req := <-c.outgoingChannel: 158 logrus.WithField("req", req).Trace("physical communicator got a request from outgoing channel") 159 go c.handleRequest(req) 160 case <-c.quit: 161 return 162 } 163 } 164 165 } 166 167 func (c *LibP2pPhysicalCommunicator) Stop() { 168 close(c.quit) 169 // shut the node down 170 if err := c.node.Close(); err != nil { 171 panic(err) 172 } 173 } 174 175 func (c *LibP2pPhysicalCommunicator) GetIncomingChannel() chan *WireMessage { 176 return c.incomingChannel 177 } 178 179 func (c *LibP2pPhysicalCommunicator) makeHost(priv core.PrivKey) (host.Host, error) { 180 opts := []libp2p.Option{ 181 libp2p.ListenAddrStrings(fmt.Sprintf("/ip4/127.0.0.1/%s/%d", IpLayerProtocol, c.Port)), 182 libp2p.Identity(priv), 183 libp2p.DisableRelay(), 184 } 185 basicHost, err := libp2p.New(context.Background(), opts...) 186 if err != nil { 187 return nil, err 188 } 189 return basicHost, nil 190 } 191 192 func (c *LibP2pPhysicalCommunicator) printHostInfo(basicHost host.Host) { 193 194 // print the node's listening addresses 195 // protocol is always p2p 196 hostAddr, err := multiaddr.NewMultiaddr(fmt.Sprintf("/p2p/%s", basicHost.ID().Pretty())) 197 if err != nil { 198 panic(err) 199 } 200 201 addr := basicHost.Addrs()[0] 202 fullAddr := addr.Encapsulate(hostAddr) 203 log.Printf("I am %s\n", fullAddr) 204 } 205 206 func (c *LibP2pPhysicalCommunicator) Listen() { 207 // start a libp2p node with default settings 208 host, err := c.makeHost(c.PrivateKey) 209 if err != nil { 210 panic(err) 211 } 212 c.node = host 213 214 c.printHostInfo(c.node) 215 216 c.node.SetStreamHandler(ProtocolId, c.HandlePeerStream) 217 c.initWait.Done() 218 logrus.Info("waiting for connection...") 219 select { 220 case <-c.quit: 221 err := c.node.Close() 222 if err != nil { 223 logrus.WithError(err).Warn("closing communicator") 224 } 225 } 226 } 227 228 func (c *LibP2pPhysicalCommunicator) HandlePeerStream(s network.Stream) { 229 // must lock to prevent double channel 230 c.mu.Lock() 231 defer c.mu.Unlock() 232 233 logrus.WithFields(logrus.Fields{ 234 "peerId": s.Conn().RemotePeer().String(), 235 "address": s.Conn().RemoteMultiaddr().String(), 236 }).Info("Peer connection established") 237 peerId := s.Conn().RemotePeer() 238 239 // deregister in the trying list 240 delete(c.tryingPeers, s.Conn().RemotePeer()) 241 242 // prevent double channel 243 if _, ok := c.activePeers[peerId]; ok { 244 // already established. close 245 err := s.Close() 246 if err != nil { 247 logrus.WithError(err).Warn("closing peer") 248 } 249 return 250 } 251 252 neightbour := &Neighbour{ 253 Id: peerId, 254 Stream: s, 255 IoEventChannel: c.ioEventChannel, 256 IncomingChannel: c.incomingChannel, 257 } 258 neightbour.InitDefault() 259 c.activePeers[peerId] = neightbour 260 261 go neightbour.StartRead() 262 go neightbour.StartWrite() 263 } 264 265 func (c *LibP2pPhysicalCommunicator) ClosePeer(id string) { 266 267 } 268 269 func (c *LibP2pPhysicalCommunicator) GetNeighbour(id string) (neighbour *Neighbour, err error) { 270 idp, err := peer.Decode(id) 271 if err != nil { 272 return 273 } 274 neighbour, ok := c.activePeers[idp] 275 if !ok { 276 err = errors.New("peer not active") 277 } 278 return 279 } 280 281 // SuggestConnection takes a peer address and try to connect to it. 282 func (c *LibP2pPhysicalCommunicator) SuggestConnection(address string) (peerIds string) { 283 c.initWait.Wait() 284 logrus.WithField("address", address).Info("registering address") 285 fullAddr, err := multiaddr.NewMultiaddr(address) 286 if err != nil { 287 logrus.WithField("address", address).WithError(err).Warn("bad address") 288 return 289 } 290 291 // p2p layer address 292 p2pAddr, err := fullAddr.ValueForProtocol(multiaddr.P_P2P) 293 294 if err != nil { 295 logrus.WithField("address", address).WithError(err).Warn("bad address") 296 } 297 298 protocolAddr, err := multiaddr.NewMultiaddr(fmt.Sprintf("/p2p/%s", p2pAddr)) 299 300 if err != nil { 301 logrus.WithField("address", address).WithError(err).Warn("bad address") 302 } 303 // keep only the connection info, wipe out the p2p layer 304 connectionAddr := fullAddr.Decapsulate(protocolAddr) 305 //fmt.Println("connectionAddr:" + connectionAddr.String()) 306 307 // recover peerId from Base58 Encoded p2pAddr 308 peerId, err := peer.Decode(p2pAddr) 309 if err != nil { 310 logrus.WithField("address", address).WithError(err).Warn("bad address") 311 } 312 peerIds = peerId.String() 313 314 //fmt.Println("peerId:" + p2pAddr) 315 // check if it is a self connection. 316 if peerId == c.node.ID() { 317 return 318 } 319 320 // save address and peer info 321 c.node.Peerstore().AddAddr(peerId, connectionAddr, peerstore.PermanentAddrTTL) 322 323 // reg in the trying list 324 c.mu.Lock() 325 defer c.mu.Unlock() 326 if _, ok := c.tryingPeers[peerId]; ok { 327 return 328 } 329 c.tryingPeers[peerId] = true 330 return 331 } 332 333 func (c *LibP2pPhysicalCommunicator) Enqueue(req *OutgoingRequest) { 334 logrus.WithField("req", req).Info("Sending message") 335 c.initWait.Wait() 336 <-ffchan.NewTimeoutSenderShort(c.outgoingChannel, req, "enqueue").C 337 //c.outgoingChannel <- req 338 } 339 340 // we use direct connection currently so let's build a connection if not exists. 341 func (c *LibP2pPhysicalCommunicator) handleRequest(req *OutgoingRequest) { 342 logrus.Trace("handling send request") 343 if req.SendType == SendTypeBroadcast { 344 for _, neighbour := range c.activePeers { 345 go neighbour.Send(req.Msg) 346 } 347 return 348 } 349 // find neighbour first 350 for _, peerIdEncoded := range req.EndReceivers { 351 peerId, err := peer.Decode(peerIdEncoded) 352 if err != nil { 353 logrus.WithError(err).WithField("peerIdEncoded", peerIdEncoded).Warn("decoding peer") 354 } 355 logrus.WithField("peerId", peerId).Trace("handling sending requets") 356 // get active neighbour 357 neighbour, ok := c.activePeers[peerId] 358 if !ok { 359 // wait for node to be connected. currently node address are pre-located and connections are built ahead. 360 logrus.WithField("peerId", peerId).Trace("connection not in active peers") 361 continue 362 } 363 logrus.WithField("peerId", peerId).Trace("go send") 364 go neighbour.Send(req.Msg) 365 } 366 } 367 368 func (c *LibP2pPhysicalCommunicator) pickOneAndConnect() { 369 c.mu.RLock() 370 371 if len(c.tryingPeers) == 0 { 372 c.mu.RUnlock() 373 return 374 } 375 peerIds := []peer.ID{} 376 for k, _ := range c.tryingPeers { 377 peerIds = append(peerIds, k) 378 } 379 c.mu.RUnlock() 380 381 peerId := peerIds[rand.Intn(len(peerIds))] 382 383 // start a stream 384 logrus.WithField("peerId", peerId).Trace("connecting peer") 385 s, err := c.node.NewStream(context.Background(), peerId, ProtocolId) 386 if err != nil { 387 if err != swarm.ErrDialBackoff { 388 //logrus.WithField("stream", s).WithError(err).Warn("error on starting stream") 389 } 390 return 391 } 392 // stream built 393 // release the lock 394 c.HandlePeerStream(s) 395 396 //hub.handleStream(s) 397 //// Create a buffered stream so that read and writes are non blocking. 398 //rw := bufio.NewReadWriter(bufio.NewReader(s), bufio.NewWriter(s)) 399 // 400 //// Create a thread to read and write data. 401 //go hub.writeData(rw) 402 //go hub.readData(rw) 403 //logrus.WithField("s", info).WithError(err).Warn("connection established") 404 } 405 406 func (c *LibP2pPhysicalCommunicator) recoverPeer() { 407 for { 408 select { 409 case <-c.quit: 410 return 411 case event := <-c.ioEventChannel: 412 c.reportPeerDown(event.Neighbour) 413 default: 414 time.Sleep(time.Second * 1) // at least sleep one second to prevent flood 415 c.pickOneAndConnect() 416 } 417 } 418 } 419 420 func (c *LibP2pPhysicalCommunicator) reportPeerDown(neighbour *Neighbour) { 421 c.mu.Lock() 422 defer c.mu.Unlock() 423 delete(c.activePeers, neighbour.Id) 424 c.tryingPeers[neighbour.Id] = true 425 }