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.

120 lines
4.0 KiB

  1. package p2p
  2. import (
  3. "sync"
  4. "github.com/gogo/protobuf/proto"
  5. )
  6. // ChannelID is an arbitrary channel ID.
  7. type ChannelID uint16
  8. // Envelope specifies the message receiver and sender.
  9. type Envelope struct {
  10. From NodeID // Message sender, or empty for outbound messages.
  11. To NodeID // Message receiver, or empty for inbound messages.
  12. Broadcast bool // Send message to all connected peers, ignoring To.
  13. Message proto.Message // Payload.
  14. }
  15. // Channel is a bidirectional channel for Protobuf message exchange with peers.
  16. // A Channel is safe for concurrent use by multiple goroutines.
  17. type Channel struct {
  18. closeOnce sync.Once
  19. // id defines the unique channel ID.
  20. id ChannelID
  21. // messageType specifies the type of messages exchanged via the channel, and
  22. // is used e.g. for automatic unmarshaling.
  23. messageType proto.Message
  24. // inCh is a channel for receiving inbound messages. Envelope.From is always
  25. // set.
  26. inCh chan Envelope
  27. // outCh is a channel for sending outbound messages. Envelope.To or Broadcast
  28. // must be set, otherwise the message is discarded.
  29. outCh chan Envelope
  30. // errCh is a channel for reporting peer errors to the router, typically used
  31. // when peers send an invalid or malignant message.
  32. errCh chan PeerError
  33. // doneCh is used to signal that a Channel is closed. A Channel is bi-directional
  34. // and should be closed by the reactor, where as the router is responsible
  35. // for explicitly closing the internal In channel.
  36. doneCh chan struct{}
  37. }
  38. // NewChannel returns a reference to a new p2p Channel. It is the reactor's
  39. // responsibility to close the Channel. After a channel is closed, the router may
  40. // safely and explicitly close the internal In channel.
  41. func NewChannel(id ChannelID, mType proto.Message, in, out chan Envelope, errCh chan PeerError) *Channel {
  42. return &Channel{
  43. id: id,
  44. messageType: mType,
  45. inCh: in,
  46. outCh: out,
  47. errCh: errCh,
  48. doneCh: make(chan struct{}),
  49. }
  50. }
  51. // ID returns the Channel's ID.
  52. func (c *Channel) ID() ChannelID {
  53. return c.id
  54. }
  55. // In returns a read-only inbound go channel. This go channel should be used by
  56. // reactors to consume Envelopes sent from peers.
  57. func (c *Channel) In() <-chan Envelope {
  58. return c.inCh
  59. }
  60. // Out returns a write-only outbound go channel. This go channel should be used
  61. // by reactors to route Envelopes to other peers.
  62. func (c *Channel) Out() chan<- Envelope {
  63. return c.outCh
  64. }
  65. // Error returns a write-only outbound go channel designated for peer errors only.
  66. // This go channel should be used by reactors to send peer errors when consuming
  67. // Envelopes sent from other peers.
  68. func (c *Channel) Error() chan<- PeerError {
  69. return c.errCh
  70. }
  71. // Close closes the outbound channel and marks the Channel as done. Internally,
  72. // the outbound outCh and peer error errCh channels are closed. It is the reactor's
  73. // responsibility to invoke Close. Any send on the Out or Error channel will
  74. // panic after the Channel is closed.
  75. //
  76. // NOTE: After a Channel is closed, the router may safely assume it can no longer
  77. // send on the internal inCh, however it should NEVER explicitly close it as
  78. // that could result in panics by sending on a closed channel.
  79. func (c *Channel) Close() {
  80. c.closeOnce.Do(func() {
  81. close(c.doneCh)
  82. close(c.outCh)
  83. close(c.errCh)
  84. })
  85. }
  86. // Done returns the Channel's internal channel that should be used by a router
  87. // to signal when it is safe to send on the internal inCh go channel.
  88. func (c *Channel) Done() <-chan struct{} {
  89. return c.doneCh
  90. }
  91. // Wrapper is a Protobuf message that can contain a variety of inner messages.
  92. // If a Channel's message type implements Wrapper, the channel will
  93. // automatically (un)wrap passed messages using the container type, such that
  94. // the channel can transparently support multiple message types.
  95. type Wrapper interface {
  96. // Wrap will take a message and wrap it in this one.
  97. Wrap(proto.Message) error
  98. // Unwrap will unwrap the inner message contained in this message.
  99. Unwrap() (proto.Message, error)
  100. }