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 = &notifiers{
    80  		block:  blockNotifier,
    81  		status: statusNotifier,
    82  	}
    83  	n.notifiersByChannel[channelName] = result
    84  
    85  	return result, nil
    86  }