github.com/status-im/status-go@v1.1.0/services/subscriptions/subscription.go (about) 1 package subscriptions 2 3 import ( 4 "errors" 5 "fmt" 6 "sync" 7 "time" 8 ) 9 10 type SubscriptionID string 11 12 type Subscription struct { 13 mu sync.RWMutex 14 id SubscriptionID 15 signal *filterSignal 16 quit chan struct{} 17 filter filter 18 started bool 19 } 20 21 func NewSubscription(namespace string, filter filter) *Subscription { 22 subscriptionID := NewSubscriptionID(namespace, filter.getID()) 23 return &Subscription{ 24 id: subscriptionID, 25 signal: newFilterSignal(string(subscriptionID)), 26 filter: filter, 27 } 28 } 29 30 func (s *Subscription) Start(checkPeriod time.Duration) error { 31 s.mu.Lock() 32 if s.started { 33 s.mu.Unlock() 34 return errors.New("subscription already started or used") 35 } 36 s.started = true 37 s.quit = make(chan struct{}) 38 quit := s.quit 39 s.mu.Unlock() 40 41 ticker := time.NewTicker(checkPeriod) 42 defer ticker.Stop() 43 44 for { 45 select { 46 case <-ticker.C: 47 filterData, err := s.filter.getChanges() 48 if err != nil { 49 s.signal.SendError(err) 50 } else if len(filterData) > 0 { 51 s.signal.SendData(filterData) 52 } 53 case <-quit: 54 return nil 55 } 56 } 57 } 58 59 func (s *Subscription) Stop(uninstall bool) error { 60 s.mu.Lock() 61 defer s.mu.Unlock() 62 if !s.started { 63 return nil 64 } 65 select { 66 case _, ok := <-s.quit: 67 // handle a case of a closed channel 68 if !ok { 69 return nil 70 } 71 default: 72 close(s.quit) 73 } 74 if !uninstall { 75 return nil 76 } 77 return s.filter.uninstall() 78 } 79 80 func NewSubscriptionID(namespace, filterID string) SubscriptionID { 81 return SubscriptionID(fmt.Sprintf("%s-%s", namespace, filterID)) 82 }