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.

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