github.com/consideritdone/landslidecore@v0.0.0-20230718131026-a8b21c5cf8a7/libs/pubsub/subscription.go (about)

     1  package pubsub
     2  
     3  import (
     4  	"errors"
     5  
     6  	tmsync "github.com/consideritdone/landslidecore/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  // nolint: misspell
    47  // Cancelled returns a channel that's closed when the subscription is
    48  // terminated and supposed to be used in a select statement.
    49  func (s *Subscription) Cancelled() <-chan struct{} {
    50  	return s.canceled
    51  }
    52  
    53  // Err returns nil if the channel returned is not yet closed.
    54  // If the channel is closed, Err returns a non-nil error explaining why:
    55  //   - ErrUnsubscribed if the subscriber choose to unsubscribe,
    56  //   - ErrOutOfCapacity if the subscriber is not pulling messages fast enough
    57  //     and the channel returned by Out became full,
    58  //
    59  // After Err returns a non-nil error, successive calls to Err return the same
    60  // error.
    61  func (s *Subscription) Err() error {
    62  	s.mtx.RLock()
    63  	defer s.mtx.RUnlock()
    64  	return s.err
    65  }
    66  
    67  func (s *Subscription) cancel(err error) {
    68  	s.mtx.Lock()
    69  	s.err = err
    70  	s.mtx.Unlock()
    71  	close(s.canceled)
    72  }
    73  
    74  // Message glues data and events together.
    75  type Message struct {
    76  	data   interface{}
    77  	events map[string][]string
    78  }
    79  
    80  func NewMessage(data interface{}, events map[string][]string) Message {
    81  	return Message{data, events}
    82  }
    83  
    84  // Data returns an original data published.
    85  func (msg Message) Data() interface{} {
    86  	return msg.data
    87  }
    88  
    89  // Events returns events, which matched the client's query.
    90  func (msg Message) Events() map[string][]string {
    91  	return msg.events
    92  }