github.com/vipernet-xyz/tm@v0.34.24/libs/pubsub/subscription.go (about)

     1  package pubsub
     2  
     3  import (
     4  	"errors"
     5  
     6  	tmsync "github.com/vipernet-xyz/tm/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("internal subscription event buffer is out of capacity")
    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  	canceled 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  		canceled: 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.canceled
    50  }
    51  
    52  // Err returns nil if the channel returned 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  //
    58  // After Err returns a non-nil error, successive calls to Err return the same
    59  // error.
    60  func (s *Subscription) Err() error {
    61  	s.mtx.RLock()
    62  	defer s.mtx.RUnlock()
    63  	return s.err
    64  }
    65  
    66  func (s *Subscription) cancel(err error) {
    67  	s.mtx.Lock()
    68  	s.err = err
    69  	s.mtx.Unlock()
    70  	close(s.canceled)
    71  }
    72  
    73  // Message glues data and events together.
    74  type Message struct {
    75  	data   interface{}
    76  	events map[string][]string
    77  }
    78  
    79  func NewMessage(data interface{}, events map[string][]string) Message {
    80  	return Message{data, events}
    81  }
    82  
    83  // Data returns an original data published.
    84  func (msg Message) Data() interface{} {
    85  	return msg.data
    86  }
    87  
    88  // Events returns events, which matched the client's query.
    89  func (msg Message) Events() map[string][]string {
    90  	return msg.events
    91  }