package event import ( "context" "fmt" "runtime/debug" "sync" "time" "bet24.com/log" ) type IEventChan interface { OnEvent() //Dispatch(ch chan<- interface{}) } type EventChan_base struct { EventFunc func(arg string) Arg string obj chan interface{} } func (e *EventChan_base) OnEvent() { if e.EventFunc != nil { e.EventFunc(e.Arg) } } func (ei *EventChan_base) isSame(ei2 *EventChan_base) bool { if ei2 == nil { return false } if fmt.Sprintf("%p", ei.obj) != fmt.Sprintf("%p", ei2.obj) { return false } return fmt.Sprintf("%p", ei.EventFunc) == fmt.Sprintf("%p", ei2.EventFunc) } func (ei *EventChan_base) isSameObject(obj interface{}) bool { if obj == nil { return false } return fmt.Sprintf("%p", ei.obj) == fmt.Sprintf("%p", obj) } type event_chan struct { sync.RWMutex events map[string][]EventChan_base } var g = newEvent() func newEvent() *event_chan { return &event_chan{ events: make(map[string][]EventChan_base), } } func hasFunc(name string, ei *EventChan_base) bool { evt, ok := g.events[name] if !ok { return false } for _, f := range evt { if f.isSame(ei) { return true } } return false } func AddEvent(name string, obj chan interface{}, fn func(arg string)) { g.Lock() defer g.Unlock() if obj == nil || fn == nil { log.Release("AddEvent no obj or f %v", name) return } ei := EventChan_base{obj: obj, EventFunc: fn} if hasFunc(name, &ei) { log.Release("AddEvent same event %v", name) return } g.events[name] = append(g.events[name], ei) } func RemoveEvent(name string, obj chan interface{}, fn func(arg string)) { g.Lock() defer g.Unlock() if obj == nil || fn == nil { log.Release("RemoveEvent no obj or fn %v", name) return } evt, ok := g.events[name] if !ok { log.Release("RemoveEvent event name not found: %s", name) return } ei := EventChan_base{obj: obj, EventFunc: fn} //for k, f := range evt { for i := 0; i < len(evt); { if evt[i].isSame(&ei) { log.Debug("Removing Event %v,%v", name, evt[i]) evt = append(evt[:i], evt[i+1:]...) } else { i++ } } g.events[name] = evt //} if len(g.events[name]) == 0 { log.Debug("Remove name: %s", name) delete(g.events, name) } } // 删除对象所有事件 func RemoveAllEvent(obj interface{}) { if obj == nil { log.Release("RemoveAllEvent no obj") return } g.Lock() for name, evt := range g.events { for i := 0; i < len(evt); { if evt[i].isSameObject(obj) { evt = append(evt[:i], evt[i+1:]...) } else { i++ } } if len(evt) > 0 { g.events[name] = evt } else { delete(g.events, name) } } g.Unlock() } func DispatchEvent(eventName, eventArg string) { go func(n, a string) { g.RLock() fns := g.events[n] g.RUnlock() if len(fns) == 0 { return } defer func() { if err := recover(); err != nil { log.Release("DispatchEvent recover err %v", err) log.Release("%s", debug.Stack()) } }() for i := len(fns) - 1; i >= 0; i-- { obj := fns[i] obj.Arg = a //log.Debug("Dispatching event %v:%v", eventName, obj) ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*500) select { case <-ctx.Done(): //log.Release("Dispatch event timeout %v:%v", eventName, obj) //RemoveEvent(n, fns[i].obj, fns[i].EventFunc) break case fns[i].obj <- &(obj): break } cancel() } }(eventName, eventArg) } func Dump() { go func() { g.RLock() defer g.RUnlock() for name, fns := range g.events { log.Release("event name[%v],count[%d]", name, len(fns)) for _, v := range fns { log.Release("event func %v", v) } } }() }