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 }