2011-07-27 20:00:23 +00:00
|
|
|
package event
|
2011-07-27 15:54:49 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"container/list"
|
|
|
|
"strings"
|
|
|
|
"sync/atomic"
|
|
|
|
"sync"
|
|
|
|
)
|
|
|
|
|
|
|
|
type HandlerID uint32
|
2011-09-12 22:25:09 +00:00
|
|
|
|
2011-07-27 15:54:49 +00:00
|
|
|
var hidCounter uint32 = 0
|
|
|
|
|
|
|
|
func NewHandlerID() HandlerID {
|
|
|
|
return HandlerID(atomic.AddUint32(&hidCounter, 1))
|
|
|
|
}
|
|
|
|
|
2011-07-27 16:49:34 +00:00
|
|
|
type Handler interface {
|
|
|
|
Run(...interface{})
|
|
|
|
Id() HandlerID
|
|
|
|
}
|
|
|
|
|
|
|
|
type basicHandler struct {
|
2011-09-12 22:25:09 +00:00
|
|
|
fn func(...interface{})
|
|
|
|
id HandlerID
|
2011-07-27 16:49:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (h *basicHandler) Run(ev ...interface{}) {
|
|
|
|
h.fn(ev...)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (h *basicHandler) Id() HandlerID {
|
|
|
|
return h.id
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewHandler(h func(...interface{})) Handler {
|
|
|
|
return &basicHandler{h, NewHandlerID()}
|
2011-07-27 15:54:49 +00:00
|
|
|
}
|
|
|
|
|
2011-07-27 20:35:45 +00:00
|
|
|
type EventDispatcher interface {
|
2011-09-12 22:25:09 +00:00
|
|
|
Dispatch(name string, ev ...interface{})
|
2011-07-27 20:35:45 +00:00
|
|
|
}
|
|
|
|
|
2011-07-27 15:54:49 +00:00
|
|
|
type EventRegistry interface {
|
2011-07-27 16:49:34 +00:00
|
|
|
AddHandler(name string, h Handler)
|
|
|
|
DelHandler(h Handler)
|
2011-07-27 15:54:49 +00:00
|
|
|
Dispatch(name string, ev ...interface{})
|
|
|
|
ClearEvents(name string)
|
|
|
|
}
|
|
|
|
|
|
|
|
type registry struct {
|
|
|
|
// Event registry as a lockable map of linked-lists
|
|
|
|
sync.RWMutex
|
2011-09-12 22:25:09 +00:00
|
|
|
events map[string]*list.List
|
2011-07-27 16:49:34 +00:00
|
|
|
dispatcher func(r *registry, name string, ev ...interface{})
|
2011-09-12 22:25:09 +00:00
|
|
|
}
|
2011-07-27 15:54:49 +00:00
|
|
|
|
2011-07-27 19:59:58 +00:00
|
|
|
func NewRegistry() EventRegistry {
|
2011-07-27 15:54:49 +00:00
|
|
|
r := ®istry{events: make(map[string]*list.List)}
|
|
|
|
r.Parallel()
|
|
|
|
return r
|
|
|
|
}
|
|
|
|
|
2011-07-27 16:49:34 +00:00
|
|
|
func (r *registry) AddHandler(name string, h Handler) {
|
2011-07-27 15:54:49 +00:00
|
|
|
name = strings.ToLower(name)
|
|
|
|
r.Lock()
|
|
|
|
defer r.Unlock()
|
|
|
|
if _, ok := r.events[name]; !ok {
|
|
|
|
r.events[name] = list.New()
|
|
|
|
}
|
|
|
|
for e := r.events[name].Front(); e != nil; e = e.Next() {
|
|
|
|
// Check we're not adding a duplicate handler to this event
|
2011-07-27 16:49:34 +00:00
|
|
|
if e.Value.(Handler).Id() == h.Id() {
|
2011-07-27 15:54:49 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
r.events[name].PushBack(h)
|
|
|
|
}
|
|
|
|
|
2011-07-27 16:49:34 +00:00
|
|
|
func (r *registry) DelHandler(h Handler) {
|
2011-07-27 15:54:49 +00:00
|
|
|
// This is a bit brute-force. Don't add too many handlers!
|
|
|
|
r.Lock()
|
|
|
|
defer r.Unlock()
|
|
|
|
for _, l := range r.events {
|
|
|
|
for e := l.Front(); e != nil; e = e.Next() {
|
2011-07-27 16:49:34 +00:00
|
|
|
if e.Value.(Handler).Id() == h.Id() {
|
2011-07-27 15:54:49 +00:00
|
|
|
l.Remove(e)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *registry) Dispatch(name string, ev ...interface{}) {
|
2011-07-27 16:49:34 +00:00
|
|
|
r.dispatcher(r, name, ev...)
|
2011-07-27 15:54:49 +00:00
|
|
|
}
|
|
|
|
|
2011-07-27 19:59:58 +00:00
|
|
|
func (r *registry) ClearEvents(name string) {
|
|
|
|
r.Lock()
|
|
|
|
defer r.Unlock()
|
|
|
|
if l, ok := r.events[name]; ok {
|
|
|
|
l.Init()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-27 15:54:49 +00:00
|
|
|
func (r *registry) Parallel() {
|
2011-07-27 16:49:34 +00:00
|
|
|
r.dispatcher = (*registry).parallelDispatch
|
2011-07-27 15:54:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (r *registry) Serial() {
|
2011-07-27 16:49:34 +00:00
|
|
|
r.dispatcher = (*registry).serialDispatch
|
2011-07-27 15:54:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (r *registry) parallelDispatch(name string, ev ...interface{}) {
|
|
|
|
name = strings.ToLower(name)
|
|
|
|
r.RLock()
|
|
|
|
defer r.RUnlock()
|
|
|
|
if l, ok := r.events[name]; ok {
|
|
|
|
for e := l.Front(); e != nil; e = e.Next() {
|
2011-07-27 16:49:34 +00:00
|
|
|
h := e.Value.(Handler)
|
|
|
|
go h.Run(ev...)
|
2011-07-27 15:54:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *registry) serialDispatch(name string, ev ...interface{}) {
|
|
|
|
name = strings.ToLower(name)
|
|
|
|
r.RLock()
|
|
|
|
defer r.RUnlock()
|
|
|
|
if l, ok := r.events[name]; ok {
|
2011-07-27 16:49:34 +00:00
|
|
|
hlist := make([]Handler, 0, l.Len())
|
2011-07-27 15:54:49 +00:00
|
|
|
for e := l.Front(); e != nil; e = e.Next() {
|
2011-07-27 16:49:34 +00:00
|
|
|
hlist = append(hlist, e.Value.(Handler))
|
2011-07-27 15:54:49 +00:00
|
|
|
}
|
|
|
|
go func() {
|
|
|
|
for _, h := range hlist {
|
2011-07-27 16:49:34 +00:00
|
|
|
h.Run(ev...)
|
2011-07-27 15:54:49 +00:00
|
|
|
}
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
}
|