github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/internal/pkg/gateway/commit/notifier.go (about) 1 /* 2 Copyright hechain. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package commit 8 9 import ( 10 "sync" 11 12 "github.com/hechain20/hechain/core/ledger" 13 ) 14 15 // NotificationSupplier obtains a commit notification channel for a specific ledger. It provides an abstraction of the use of 16 // Peer, Channel and Ledger to obtain this result, and allows mocking in unit tests. 17 type NotificationSupplier interface { 18 CommitNotifications(done <-chan struct{}, channelName string) (<-chan *ledger.CommitNotification, error) 19 } 20 21 type notifiers struct { 22 block *blockNotifier 23 status *statusNotifier 24 } 25 26 // Notifier provides notification of transaction commits. 27 type Notifier struct { 28 supplier NotificationSupplier 29 lock sync.Mutex 30 notifiersByChannel map[string]*notifiers 31 cancel chan struct{} 32 once sync.Once 33 } 34 35 func NewNotifier(supplier NotificationSupplier) *Notifier { 36 return &Notifier{ 37 supplier: supplier, 38 notifiersByChannel: make(map[string]*notifiers), 39 cancel: make(chan struct{}), 40 } 41 } 42 43 // notifyStatus notifies the caller when the named transaction commits on the named channel. The caller is only notified 44 // of commits occurring after registering for notifications. 45 func (n *Notifier) notifyStatus(done <-chan struct{}, channelName string, transactionID string) (<-chan *Status, error) { 46 notifiers, err := n.notifiersForChannel(channelName) 47 if err != nil { 48 return nil, err 49 } 50 51 notifyChannel := notifiers.status.registerListener(done, transactionID) 52 return notifyChannel, nil 53 } 54 55 // close the notifier. This closes all notification channels obtained from this notifier. Behavior is undefined after 56 // closing and the notifier should not be used. 57 func (n *Notifier) close() { 58 n.once.Do(func() { 59 close(n.cancel) 60 }) 61 } 62 63 func (n *Notifier) notifiersForChannel(channelName string) (*notifiers, error) { 64 n.lock.Lock() 65 defer n.lock.Unlock() 66 67 result := n.notifiersByChannel[channelName] 68 if result != nil && !result.block.isClosed() { 69 return result, nil 70 } 71 72 commitChannel, err := n.supplier.CommitNotifications(n.cancel, channelName) 73 if err != nil { 74 return nil, err 75 } 76 77 statusNotifier := newStatusNotifier() 78 blockNotifier := newBlockNotifier(n.cancel, commitChannel, statusNotifier) 79 result = ¬ifiers{ 80 block: blockNotifier, 81 status: statusNotifier, 82 } 83 n.notifiersByChannel[channelName] = result 84 85 return result, nil 86 }