github.com/number571/tendermint@v0.34.11-gost/libs/pubsub/subscription.go (about) 1 package pubsub 2 3 import ( 4 "errors" 5 "fmt" 6 7 "github.com/number571/tendermint/abci/types" 8 tmsync "github.com/number571/tendermint/internal/libs/sync" 9 "github.com/google/uuid" 10 ) 11 12 var ( 13 // ErrUnsubscribed is returned by Err when a client unsubscribes. 14 ErrUnsubscribed = errors.New("client unsubscribed") 15 16 // ErrOutOfCapacity is returned by Err when a client is not pulling messages 17 // fast enough. Note the client's subscription will be terminated. 18 ErrOutOfCapacity = errors.New("client is not pulling messages fast enough") 19 ) 20 21 // A Subscription represents a client subscription for a particular query and 22 // consists of three things: 23 // 1) channel onto which messages and events are published 24 // 2) channel which is closed if a client is too slow or choose to unsubscribe 25 // 3) err indicating the reason for (2) 26 type Subscription struct { 27 id string 28 out chan Message 29 30 canceled chan struct{} 31 mtx tmsync.RWMutex 32 err error 33 } 34 35 // NewSubscription returns a new subscription with the given outCapacity. 36 func NewSubscription(outCapacity int) *Subscription { 37 return &Subscription{ 38 id: uuid.NewString(), 39 out: make(chan Message, outCapacity), 40 canceled: make(chan struct{}), 41 } 42 } 43 44 // Out returns a channel onto which messages and events are published. 45 // Unsubscribe/UnsubscribeAll does not close the channel to avoid clients from 46 // receiving a nil message. 47 func (s *Subscription) Out() <-chan Message { 48 return s.out 49 } 50 51 func (s *Subscription) ID() string { return s.id } 52 53 // Canceled returns a channel that's closed when the subscription is 54 // terminated and supposed to be used in a select statement. 55 func (s *Subscription) Canceled() <-chan struct{} { 56 return s.canceled 57 } 58 59 // Err returns nil if the channel returned by Canceled is not yet closed. 60 // If the channel is closed, Err returns a non-nil error explaining why: 61 // - ErrUnsubscribed if the subscriber choose to unsubscribe, 62 // - ErrOutOfCapacity if the subscriber is not pulling messages fast enough 63 // and the channel returned by Out became full, 64 // After Err returns a non-nil error, successive calls to Err return the same 65 // error. 66 func (s *Subscription) Err() error { 67 s.mtx.RLock() 68 defer s.mtx.RUnlock() 69 return s.err 70 } 71 72 func (s *Subscription) cancel(err error) { 73 s.mtx.Lock() 74 defer s.mtx.Unlock() 75 defer func() { 76 perr := recover() 77 if err == nil && perr != nil { 78 err = fmt.Errorf("problem closing subscription: %v", perr) 79 } 80 }() 81 82 if s.err == nil && err != nil { 83 s.err = err 84 } 85 86 close(s.canceled) 87 } 88 89 // Message glues data and events together. 90 type Message struct { 91 subID string 92 data interface{} 93 events []types.Event 94 } 95 96 func NewMessage(subID string, data interface{}, events []types.Event) Message { 97 return Message{ 98 subID: subID, 99 data: data, 100 events: events, 101 } 102 } 103 104 // SubscriptionID returns the unique identifier for the subscription 105 // that produced this message. 106 func (msg Message) SubscriptionID() string { return msg.subID } 107 108 // Data returns an original data published. 109 func (msg Message) Data() interface{} { return msg.data } 110 111 // Events returns events, which matched the client's query. 112 func (msg Message) Events() []types.Event { return msg.events }