github.com/enbility/spine-go@v0.7.0/spine/events.go (about) 1 package spine 2 3 import ( 4 "sync" 5 6 "github.com/enbility/spine-go/api" 7 ) 8 9 var Events events 10 11 type eventHandlerItem struct { 12 Level api.EventHandlerLevel 13 Handler api.EventHandlerInterface 14 } 15 16 type events struct { 17 mu sync.Mutex 18 muHandle sync.Mutex 19 20 handlers []eventHandlerItem // event handling outside of the core stack 21 } 22 23 // will be used in EEBUS core directly to access the level EventHandlerLevelCore 24 func (r *events) subscribe(level api.EventHandlerLevel, handler api.EventHandlerInterface) error { 25 r.mu.Lock() 26 defer r.mu.Unlock() 27 28 for _, item := range r.handlers { 29 if item.Level == level && item.Handler == handler { 30 return nil 31 } 32 } 33 34 newHandlerItem := eventHandlerItem{ 35 Level: level, 36 Handler: handler, 37 } 38 r.handlers = append(r.handlers, newHandlerItem) 39 40 return nil 41 } 42 43 // Subscribe to message events and handle them in 44 // the Eventhandler interface implementation 45 // 46 // returns an error if EventHandlerLevelCore is used as 47 // that is only allowed for internal use 48 func (r *events) Subscribe(handler api.EventHandlerInterface) error { 49 return r.subscribe(api.EventHandlerLevelApplication, handler) 50 } 51 52 // will be used in EEBUS core directly to access the level EventHandlerLevelCore 53 func (r *events) unsubscribe(level api.EventHandlerLevel, handler api.EventHandlerInterface) error { 54 r.mu.Lock() 55 defer r.mu.Unlock() 56 57 var newHandlers []eventHandlerItem 58 for _, item := range r.handlers { 59 if item.Level != level || item.Handler != handler { 60 newHandlers = append(newHandlers, item) 61 } 62 } 63 64 r.handlers = newHandlers 65 66 return nil 67 } 68 69 // Unsubscribe from getting events 70 func (r *events) Unsubscribe(handler api.EventHandlerInterface) error { 71 return r.unsubscribe(api.EventHandlerLevelApplication, handler) 72 } 73 74 // Publish an event to all subscribers 75 func (r *events) Publish(payload api.EventPayload) { 76 r.mu.Lock() 77 var handler []eventHandlerItem 78 copy(r.handlers, handler) 79 r.mu.Unlock() 80 81 // Use different locks, so unpublish is possible in the event handlers 82 r.muHandle.Lock() 83 // process subscribers by level 84 handlerLevels := []api.EventHandlerLevel{ 85 api.EventHandlerLevelCore, 86 api.EventHandlerLevelApplication, 87 } 88 89 for _, level := range handlerLevels { 90 for _, item := range r.handlers { 91 if item.Level != level { 92 continue 93 } 94 95 if level == api.EventHandlerLevelCore { 96 // do not run this asynchronously, to make sure all required 97 // and expected actions are taken 98 item.Handler.HandleEvent(payload) 99 } else { 100 go item.Handler.HandleEvent(payload) 101 } 102 } 103 } 104 r.muHandle.Unlock() 105 }