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  }