github.com/evdatsion/aphelion-dpos-bft@v0.32.1/types/event_bus.go (about) 1 package types 2 3 import ( 4 "context" 5 "fmt" 6 7 "github.com/evdatsion/aphelion-dpos-bft/abci/types" 8 cmn "github.com/evdatsion/aphelion-dpos-bft/libs/common" 9 "github.com/evdatsion/aphelion-dpos-bft/libs/log" 10 tmpubsub "github.com/evdatsion/aphelion-dpos-bft/libs/pubsub" 11 ) 12 13 const defaultCapacity = 0 14 15 type EventBusSubscriber interface { 16 Subscribe(ctx context.Context, subscriber string, query tmpubsub.Query, outCapacity ...int) (Subscription, error) 17 Unsubscribe(ctx context.Context, subscriber string, query tmpubsub.Query) error 18 UnsubscribeAll(ctx context.Context, subscriber string) error 19 20 NumClients() int 21 NumClientSubscriptions(clientID string) int 22 } 23 24 type Subscription interface { 25 Out() <-chan tmpubsub.Message 26 Cancelled() <-chan struct{} 27 Err() error 28 } 29 30 // EventBus is a common bus for all events going through the system. All calls 31 // are proxied to underlying pubsub server. All events must be published using 32 // EventBus to ensure correct data types. 33 type EventBus struct { 34 cmn.BaseService 35 pubsub *tmpubsub.Server 36 } 37 38 // NewEventBus returns a new event bus. 39 func NewEventBus() *EventBus { 40 return NewEventBusWithBufferCapacity(defaultCapacity) 41 } 42 43 // NewEventBusWithBufferCapacity returns a new event bus with the given buffer capacity. 44 func NewEventBusWithBufferCapacity(cap int) *EventBus { 45 // capacity could be exposed later if needed 46 pubsub := tmpubsub.NewServer(tmpubsub.BufferCapacity(cap)) 47 b := &EventBus{pubsub: pubsub} 48 b.BaseService = *cmn.NewBaseService(nil, "EventBus", b) 49 return b 50 } 51 52 func (b *EventBus) SetLogger(l log.Logger) { 53 b.BaseService.SetLogger(l) 54 b.pubsub.SetLogger(l.With("module", "pubsub")) 55 } 56 57 func (b *EventBus) OnStart() error { 58 return b.pubsub.Start() 59 } 60 61 func (b *EventBus) OnStop() { 62 b.pubsub.Stop() 63 } 64 65 func (b *EventBus) NumClients() int { 66 return b.pubsub.NumClients() 67 } 68 69 func (b *EventBus) NumClientSubscriptions(clientID string) int { 70 return b.pubsub.NumClientSubscriptions(clientID) 71 } 72 73 func (b *EventBus) Subscribe(ctx context.Context, subscriber string, query tmpubsub.Query, outCapacity ...int) (Subscription, error) { 74 return b.pubsub.Subscribe(ctx, subscriber, query, outCapacity...) 75 } 76 77 // This method can be used for a local consensus explorer and synchronous 78 // testing. Do not use for for public facing / untrusted subscriptions! 79 func (b *EventBus) SubscribeUnbuffered(ctx context.Context, subscriber string, query tmpubsub.Query) (Subscription, error) { 80 return b.pubsub.SubscribeUnbuffered(ctx, subscriber, query) 81 } 82 83 func (b *EventBus) Unsubscribe(ctx context.Context, subscriber string, query tmpubsub.Query) error { 84 return b.pubsub.Unsubscribe(ctx, subscriber, query) 85 } 86 87 func (b *EventBus) UnsubscribeAll(ctx context.Context, subscriber string) error { 88 return b.pubsub.UnsubscribeAll(ctx, subscriber) 89 } 90 91 func (b *EventBus) Publish(eventType string, eventData TMEventData) error { 92 // no explicit deadline for publishing events 93 ctx := context.Background() 94 return b.pubsub.PublishWithEvents(ctx, eventData, map[string][]string{EventTypeKey: {eventType}}) 95 } 96 97 // validateAndStringifyEvents takes a slice of event objects and creates a 98 // map of stringified events where each key is composed of the event 99 // type and each of the event's attributes keys in the form of 100 // "{event.Type}.{attribute.Key}" and the value is each attribute's value. 101 func (b *EventBus) validateAndStringifyEvents(events []types.Event, logger log.Logger) map[string][]string { 102 result := make(map[string][]string) 103 for _, event := range events { 104 if len(event.Type) == 0 { 105 logger.Debug("Got an event with an empty type (skipping)", "event", event) 106 continue 107 } 108 109 for _, attr := range event.Attributes { 110 if len(attr.Key) == 0 { 111 logger.Debug("Got an event attribute with an empty key(skipping)", "event", event) 112 continue 113 } 114 115 compositeTag := fmt.Sprintf("%s.%s", event.Type, string(attr.Key)) 116 result[compositeTag] = append(result[compositeTag], string(attr.Value)) 117 } 118 } 119 120 return result 121 } 122 123 func (b *EventBus) PublishEventNewBlock(data EventDataNewBlock) error { 124 // no explicit deadline for publishing events 125 ctx := context.Background() 126 127 resultEvents := append(data.ResultBeginBlock.Events, data.ResultEndBlock.Events...) 128 events := b.validateAndStringifyEvents(resultEvents, b.Logger.With("block", data.Block.StringShort())) 129 130 // add predefined new block event 131 events[EventTypeKey] = append(events[EventTypeKey], EventNewBlock) 132 133 return b.pubsub.PublishWithEvents(ctx, data, events) 134 } 135 136 func (b *EventBus) PublishEventNewBlockHeader(data EventDataNewBlockHeader) error { 137 // no explicit deadline for publishing events 138 ctx := context.Background() 139 140 resultTags := append(data.ResultBeginBlock.Events, data.ResultEndBlock.Events...) 141 // TODO: Create StringShort method for Header and use it in logger. 142 events := b.validateAndStringifyEvents(resultTags, b.Logger.With("header", data.Header)) 143 144 // add predefined new block header event 145 events[EventTypeKey] = append(events[EventTypeKey], EventNewBlockHeader) 146 147 return b.pubsub.PublishWithEvents(ctx, data, events) 148 } 149 150 func (b *EventBus) PublishEventVote(data EventDataVote) error { 151 return b.Publish(EventVote, data) 152 } 153 154 func (b *EventBus) PublishEventValidBlock(data EventDataRoundState) error { 155 return b.Publish(EventValidBlock, data) 156 } 157 158 // PublishEventTx publishes tx event with tags from Result. Note it will add 159 // predefined tags (EventTypeKey, TxHashKey). Existing tags with the same names 160 // will be overwritten. 161 func (b *EventBus) PublishEventTx(data EventDataTx) error { 162 // no explicit deadline for publishing events 163 ctx := context.Background() 164 165 events := b.validateAndStringifyEvents(data.Result.Events, b.Logger.With("tx", data.Tx)) 166 167 // add predefined tags 168 events[EventTypeKey] = append(events[EventTypeKey], EventTx) 169 events[TxHashKey] = append(events[TxHashKey], fmt.Sprintf("%X", data.Tx.Hash())) 170 events[TxHeightKey] = append(events[TxHeightKey], fmt.Sprintf("%d", data.Height)) 171 172 return b.pubsub.PublishWithEvents(ctx, data, events) 173 } 174 175 func (b *EventBus) PublishEventNewRoundStep(data EventDataRoundState) error { 176 return b.Publish(EventNewRoundStep, data) 177 } 178 179 func (b *EventBus) PublishEventTimeoutPropose(data EventDataRoundState) error { 180 return b.Publish(EventTimeoutPropose, data) 181 } 182 183 func (b *EventBus) PublishEventTimeoutWait(data EventDataRoundState) error { 184 return b.Publish(EventTimeoutWait, data) 185 } 186 187 func (b *EventBus) PublishEventNewRound(data EventDataNewRound) error { 188 return b.Publish(EventNewRound, data) 189 } 190 191 func (b *EventBus) PublishEventCompleteProposal(data EventDataCompleteProposal) error { 192 return b.Publish(EventCompleteProposal, data) 193 } 194 195 func (b *EventBus) PublishEventPolka(data EventDataRoundState) error { 196 return b.Publish(EventPolka, data) 197 } 198 199 func (b *EventBus) PublishEventUnlock(data EventDataRoundState) error { 200 return b.Publish(EventUnlock, data) 201 } 202 203 func (b *EventBus) PublishEventRelock(data EventDataRoundState) error { 204 return b.Publish(EventRelock, data) 205 } 206 207 func (b *EventBus) PublishEventLock(data EventDataRoundState) error { 208 return b.Publish(EventLock, data) 209 } 210 211 func (b *EventBus) PublishEventValidatorSetUpdates(data EventDataValidatorSetUpdates) error { 212 return b.Publish(EventValidatorSetUpdates, data) 213 } 214 215 //----------------------------------------------------------------------------- 216 type NopEventBus struct{} 217 218 func (NopEventBus) Subscribe(ctx context.Context, subscriber string, query tmpubsub.Query, out chan<- interface{}) error { 219 return nil 220 } 221 222 func (NopEventBus) Unsubscribe(ctx context.Context, subscriber string, query tmpubsub.Query) error { 223 return nil 224 } 225 226 func (NopEventBus) UnsubscribeAll(ctx context.Context, subscriber string) error { 227 return nil 228 } 229 230 func (NopEventBus) PublishEventNewBlock(data EventDataNewBlock) error { 231 return nil 232 } 233 234 func (NopEventBus) PublishEventNewBlockHeader(data EventDataNewBlockHeader) error { 235 return nil 236 } 237 238 func (NopEventBus) PublishEventVote(data EventDataVote) error { 239 return nil 240 } 241 242 func (NopEventBus) PublishEventTx(data EventDataTx) error { 243 return nil 244 } 245 246 func (NopEventBus) PublishEventNewRoundStep(data EventDataRoundState) error { 247 return nil 248 } 249 250 func (NopEventBus) PublishEventTimeoutPropose(data EventDataRoundState) error { 251 return nil 252 } 253 254 func (NopEventBus) PublishEventTimeoutWait(data EventDataRoundState) error { 255 return nil 256 } 257 258 func (NopEventBus) PublishEventNewRound(data EventDataRoundState) error { 259 return nil 260 } 261 262 func (NopEventBus) PublishEventCompleteProposal(data EventDataRoundState) error { 263 return nil 264 } 265 266 func (NopEventBus) PublishEventPolka(data EventDataRoundState) error { 267 return nil 268 } 269 270 func (NopEventBus) PublishEventUnlock(data EventDataRoundState) error { 271 return nil 272 } 273 274 func (NopEventBus) PublishEventRelock(data EventDataRoundState) error { 275 return nil 276 } 277 278 func (NopEventBus) PublishEventLock(data EventDataRoundState) error { 279 return nil 280 } 281 282 func (NopEventBus) PublishEventValidatorSetUpdates(data EventDataValidatorSetUpdates) error { 283 return nil 284 }