github.com/Finschia/ostracon@v1.1.5/p2p/base_reactor.go (about) 1 package p2p 2 3 import ( 4 "github.com/Finschia/ostracon/libs/service" 5 "github.com/Finschia/ostracon/p2p/conn" 6 ) 7 8 // Reactor is responsible for handling incoming messages on one or more 9 // Channel. Switch calls GetChannels when reactor is added to it. When a new 10 // peer joins our node, InitPeer and AddPeer are called. RemovePeer is called 11 // when the peer is stopped. Receive is called when a message is received on a 12 // channel associated with this reactor. 13 // 14 // Peer#Send or Peer#TrySend should be used to send the message to a peer. 15 type Reactor interface { 16 service.Service // Start, Stop 17 18 // SetSwitch allows setting a switch. 19 SetSwitch(*Switch) 20 21 // GetChannels returns the list of MConnection.ChannelDescriptor. Make sure 22 // that each ID is unique across all the reactors added to the switch. 23 GetChannels() []*conn.ChannelDescriptor 24 25 // InitPeer is called by the switch before the peer is started. Use it to 26 // initialize data for the peer (e.g. peer state). 27 // 28 // NOTE: The switch won't call AddPeer nor RemovePeer if it fails to start 29 // the peer. Do not store any data associated with the peer in the reactor 30 // itself unless you don't want to have a state, which is never cleaned up. 31 InitPeer(peer Peer) Peer 32 33 // AddPeer is called by the switch after the peer is added and successfully 34 // started. Use it to start goroutines communicating with the peer. 35 AddPeer(peer Peer) 36 37 // RemovePeer is called by the switch when the peer is stopped (due to error 38 // or other reason). 39 RemovePeer(peer Peer, reason interface{}) 40 41 // Receive is called by the switch when msgBytes is received from the peer. 42 // 43 // NOTE reactor can not keep msgBytes around after Receive completes without 44 // copying. 45 // 46 // CONTRACT: msgBytes are not nil. 47 // 48 // Only one of Receive or ReceiveEnvelope are called per message. If ReceiveEnvelope 49 // is implemented, it will be used, otherwise the switch will fallback to 50 // using Receive. 51 // Deprecated: Reactors looking to receive data from a peer should implement ReceiveEnvelope. 52 // Receive will be deprecated in favor of ReceiveEnvelope in v0.37. 53 Receive(chID byte, peer Peer, msgBytes []byte) 54 55 // receive async version 56 GetRecvChan() chan *BufferedMsg 57 58 // receive routine per reactor 59 RecvRoutine() 60 } 61 62 type EnvelopeReceiver interface { 63 // ReceiveEnvelope is called by the switch when an envelope is received from any connected 64 // peer on any of the channels registered by the reactor. 65 // 66 // Only one of Receive or ReceiveEnvelope are called per message. If ReceiveEnvelope 67 // is implemented, it will be used, otherwise the switch will fallback to 68 // using Receive. Receive will be replaced by ReceiveEnvelope in a future version 69 ReceiveEnvelope(Envelope) 70 } 71 72 //-------------------------------------- 73 74 type BaseReactor struct { 75 service.BaseService // Provides Start, Stop, .Quit 76 Switch *Switch 77 recvMsgBuf chan *BufferedMsg 78 impl Reactor 79 } 80 81 func NewBaseReactor(name string, impl Reactor, async bool, recvBufSize int) *BaseReactor { 82 baseReactor := &BaseReactor{ 83 BaseService: *service.NewBaseService(nil, name, impl), 84 Switch: nil, 85 impl: impl, 86 } 87 if async { 88 baseReactor.recvMsgBuf = make(chan *BufferedMsg, recvBufSize) 89 } 90 return baseReactor 91 } 92 93 func (br *BaseReactor) SetSwitch(sw *Switch) { 94 br.Switch = sw 95 } 96 func (*BaseReactor) GetChannels() []*conn.ChannelDescriptor { return nil } 97 func (*BaseReactor) AddPeer(peer Peer) {} 98 func (*BaseReactor) RemovePeer(peer Peer, reason interface{}) {} 99 func (*BaseReactor) ReceiveEnvelope(e Envelope) {} 100 func (*BaseReactor) Receive(chID byte, peer Peer, msgBytes []byte) {} 101 func (*BaseReactor) InitPeer(peer Peer) Peer { return peer } 102 103 func (br *BaseReactor) OnStart() error { 104 if br.recvMsgBuf != nil { 105 // if it is async mode it starts RecvRoutine() 106 go br.RecvRoutine() 107 } 108 return nil 109 } 110 111 func (br *BaseReactor) RecvRoutine() { 112 for { 113 select { 114 case msg := <-br.recvMsgBuf: 115 if nr, ok := br.impl.(EnvelopeReceiver); ok { 116 nr.ReceiveEnvelope(Envelope{ 117 ChannelID: msg.ChID, 118 Src: msg.Peer, 119 Message: msg.ProtoMsg, 120 }) 121 } else { 122 br.impl.Receive(msg.ChID, msg.Peer, msg.Msg) 123 } 124 case <-br.Quit(): 125 return 126 } 127 } 128 } 129 130 func (br *BaseReactor) GetRecvChan() chan *BufferedMsg { 131 if br.recvMsgBuf == nil { 132 panic("It's not async reactor, but GetRecvChan() is called ") 133 } 134 return br.recvMsgBuf 135 }