github.com/mydexchain/tendermint@v0.0.4/libs/pubsub/subscription.go (about)

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