github.com/igggame/nebulas-go@v2.1.0+incompatible/core/event.go (about)

     1  // Copyright (C) 2017 go-nebulas authors
     2  //
     3  // This file is part of the go-nebulas library.
     4  //
     5  // the go-nebulas library is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // the go-nebulas library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  // GNU General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU General Public License
    16  // along with the go-nebulas library.  If not, see <http://www.gnu.org/licenses/>.
    17  //
    18  
    19  package core
    20  
    21  import (
    22  	"sync"
    23  
    24  	"time"
    25  
    26  	"github.com/nebulasio/go-nebulas/core/state"
    27  	"github.com/nebulasio/go-nebulas/util/logging"
    28  	"github.com/sirupsen/logrus"
    29  )
    30  
    31  const (
    32  	// TopicPendingTransaction the topic of pending a transaction in transaction_pool.
    33  	TopicPendingTransaction = "chain.pendingTransaction"
    34  
    35  	// TopicLibBlock the topic of latest irreversible block.
    36  	TopicLibBlock = "chain.latestIrreversibleBlock"
    37  
    38  	// TopicTransactionExecutionResult the topic of transaction execution result
    39  	TopicTransactionExecutionResult = "chain.transactionResult"
    40  
    41  	// TopicNewTailBlock the topic of new tail block set
    42  	TopicNewTailBlock = "chain.newTailBlock"
    43  
    44  	// TopicRevertBlock the topic of revert block
    45  	TopicRevertBlock = "chain.revertBlock"
    46  
    47  	// TopicDropTransaction drop tx (1): smaller nonce (2) expire txLifeTime
    48  	TopicDropTransaction = "chain.dropTransaction"
    49  
    50  	// TopicTransferFromContract transfer from contract
    51  	TopicTransferFromContract = "chain.transferFromContract"
    52  
    53  	// TopicInnerTransferContract inner transfer
    54  	TopicInnerContract = "chain.innerContract"
    55  )
    56  
    57  // EventSubscriber subscriber object
    58  type EventSubscriber struct {
    59  	eventCh chan *state.Event
    60  	topics  []string
    61  }
    62  
    63  // NewEventSubscriber returns an EventSubscriber
    64  func NewEventSubscriber(size int, topics []string) *EventSubscriber {
    65  	eventCh := make(chan *state.Event, size)
    66  	subscriber := &EventSubscriber{
    67  		eventCh: eventCh,
    68  		topics:  topics,
    69  	}
    70  	return subscriber
    71  }
    72  
    73  // EventChan returns subscriber's eventCh
    74  func (s *EventSubscriber) EventChan() chan *state.Event {
    75  	return s.eventCh
    76  }
    77  
    78  // EventEmitter provide event functionality for Nebulas.
    79  type EventEmitter struct {
    80  	eventSubs *sync.Map
    81  	eventCh   chan *state.Event
    82  	quitCh    chan int
    83  	size      int
    84  }
    85  
    86  // NewEventEmitter return new EventEmitter.
    87  func NewEventEmitter(size int) *EventEmitter {
    88  	return &EventEmitter{
    89  		eventSubs: new(sync.Map),
    90  		eventCh:   make(chan *state.Event, size),
    91  		quitCh:    make(chan int, 1),
    92  		size:      size,
    93  	}
    94  }
    95  
    96  // Start start emitter.
    97  func (emitter *EventEmitter) Start() {
    98  	logging.CLog().WithFields(logrus.Fields{
    99  		"size": emitter.size,
   100  	}).Info("Starting EventEmitter...")
   101  
   102  	go emitter.loop()
   103  }
   104  
   105  // Stop stop emitter.
   106  func (emitter *EventEmitter) Stop() {
   107  	logging.CLog().WithFields(logrus.Fields{
   108  		"size": emitter.size,
   109  	}).Info("Stopping EventEmitter...")
   110  
   111  	emitter.quitCh <- 1
   112  }
   113  
   114  // Trigger trigger event.
   115  func (emitter *EventEmitter) Trigger(e *state.Event) {
   116  	emitter.eventCh <- e
   117  }
   118  
   119  // Register register event chan.
   120  func (emitter *EventEmitter) Register(subscribers ...*EventSubscriber) {
   121  
   122  	for _, v := range subscribers {
   123  		for _, topic := range v.topics {
   124  			m, _ := emitter.eventSubs.LoadOrStore(topic, new(sync.Map))
   125  			m.(*sync.Map).Store(v, true)
   126  		}
   127  	}
   128  }
   129  
   130  // Deregister deregister event chan.
   131  func (emitter *EventEmitter) Deregister(subscribers ...*EventSubscriber) {
   132  	for _, v := range subscribers {
   133  		for _, topic := range v.topics {
   134  			m, _ := emitter.eventSubs.Load(topic)
   135  			if m == nil {
   136  				continue
   137  			}
   138  			m.(*sync.Map).Delete(v)
   139  		}
   140  	}
   141  }
   142  
   143  func (emitter *EventEmitter) loop() {
   144  	logging.CLog().Info("Started EventEmitter.")
   145  
   146  	timerChan := time.NewTicker(time.Second).C
   147  	for {
   148  		select {
   149  		case <-timerChan:
   150  			metricsCachedEvent.Update(int64(len(emitter.eventCh)))
   151  		case <-emitter.quitCh:
   152  			logging.CLog().Info("Stopped EventEmitter.")
   153  			return
   154  		case e := <-emitter.eventCh:
   155  
   156  			topic := e.Topic
   157  			v, ok := emitter.eventSubs.Load(topic)
   158  			if !ok {
   159  				continue
   160  			}
   161  
   162  			m, _ := v.(*sync.Map)
   163  			m.Range(func(key, value interface{}) bool {
   164  				select {
   165  				case key.(*EventSubscriber).eventCh <- e:
   166  				default:
   167  					logging.VLog().WithFields(logrus.Fields{
   168  						"topic": topic,
   169  					}).Warn("timeout to dispatch event.")
   170  				}
   171  				return true
   172  			})
   173  		}
   174  	}
   175  }