github.com/vipernet-xyz/tendermint-core@v0.32.0/libs/pubsub/subscription.go (about)

     1  package pubsub
     2  
     3  import (
     4  	"errors"
     5  	"sync"
     6  )
     7  
     8  var (
     9  	// ErrUnsubscribed is returned by Err when a client unsubscribes.
    10  	ErrUnsubscribed = errors.New("client unsubscribed")
    11  
    12  	// ErrOutOfCapacity is returned by Err when a client is not pulling messages
    13  	// fast enough. Note the client's subscription will be terminated.
    14  	ErrOutOfCapacity = errors.New("client is not pulling messages fast enough")
    15  )
    16  
    17  // A Subscription represents a client subscription for a particular query and
    18  // consists of three things:
    19  // 1) channel onto which messages and events are published
    20  // 2) channel which is closed if a client is too slow or choose to unsubscribe
    21  // 3) err indicating the reason for (2)
    22  type Subscription struct {
    23  	out chan Message
    24  
    25  	cancelled chan struct{}
    26  	mtx       sync.RWMutex
    27  	err       error
    28  }
    29  
    30  // NewSubscription returns a new subscription with the given outCapacity.
    31  func NewSubscription(outCapacity int) *Subscription {
    32  	return &Subscription{
    33  		out:       make(chan Message, outCapacity),
    34  		cancelled: make(chan struct{}),
    35  	}
    36  }
    37  
    38  // Out returns a channel onto which messages and events are published.
    39  // Unsubscribe/UnsubscribeAll does not close the channel to avoid clients from
    40  // receiving a nil message.
    41  func (s *Subscription) Out() <-chan Message {
    42  	return s.out
    43  }
    44  
    45  // Cancelled returns a channel that's closed when the subscription is
    46  // terminated and supposed to be used in a select statement.
    47  func (s *Subscription) Cancelled() <-chan struct{} {
    48  	return s.cancelled
    49  }
    50  
    51  // Err returns nil if the channel returned by Cancelled is not yet closed.
    52  // If the channel is closed, Err returns a non-nil error explaining why:
    53  //   - ErrUnsubscribed if the subscriber choose to unsubscribe,
    54  //   - ErrOutOfCapacity if the subscriber is not pulling messages fast enough
    55  //   and the channel returned by Out became full,
    56  // After Err returns a non-nil error, successive calls to Err return the same
    57  // error.
    58  func (s *Subscription) Err() error {
    59  	s.mtx.RLock()
    60  	defer s.mtx.RUnlock()
    61  	return s.err
    62  }
    63  
    64  func (s *Subscription) cancel(err error) {
    65  	s.mtx.Lock()
    66  	s.err = err
    67  	s.mtx.Unlock()
    68  	close(s.cancelled)
    69  }
    70  
    71  // Message glues data and events together.
    72  type Message struct {
    73  	data   interface{}
    74  	events map[string][]string
    75  }
    76  
    77  func NewMessage(data interface{}, events map[string][]string) Message {
    78  	return Message{data, events}
    79  }
    80  
    81  // Data returns an original data published.
    82  func (msg Message) Data() interface{} {
    83  	return msg.data
    84  }
    85  
    86  // Events returns events, which matched the client's query.
    87  func (msg Message) Events() map[string][]string {
    88  	return msg.events
    89  }