Migrate to split event pkg.

This commit is contained in:
Alex Bramley 2011-11-13 14:07:19 +00:00
parent 4e4c4b6798
commit 907560b599
7 changed files with 4 additions and 517 deletions

View File

@ -3,7 +3,7 @@ package client
import ( import (
"bufio" "bufio"
"crypto/tls" "crypto/tls"
"github.com/fluffle/goirc/event" "github.com/fluffle/goevent/event"
"github.com/fluffle/golog/logging" "github.com/fluffle/golog/logging"
"github.com/fluffle/goirc/state" "github.com/fluffle/goirc/state"
"fmt" "fmt"

View File

@ -2,7 +2,7 @@ package client
import ( import (
"bufio" "bufio"
"github.com/fluffle/goirc/event" "github.com/fluffle/goevent/event"
"github.com/fluffle/golog/logging" "github.com/fluffle/golog/logging"
"github.com/fluffle/goirc/state" "github.com/fluffle/goirc/state"
"gomock.googlecode.com/hg/gomock" "gomock.googlecode.com/hg/gomock"

View File

@ -4,7 +4,7 @@ package client
// to manage tracking an irc connection etc. // to manage tracking an irc connection etc.
import ( import (
"github.com/fluffle/goirc/event" "github.com/fluffle/goevent/event"
"strings" "strings"
) )

View File

@ -4,7 +4,7 @@ package client
// to manage tracking state for an IRC connection // to manage tracking state for an IRC connection
import ( import (
"github.com/fluffle/goirc/event" "github.com/fluffle/goevent/event"
"strings" "strings"
) )

View File

@ -1,127 +0,0 @@
// Automatically generated by MockGen. DO NOT EDIT!
// Source: registry.go
package event
import (
gomock "gomock.googlecode.com/hg/gomock"
)
// Mock of Handler interface
type MockHandler struct {
ctrl *gomock.Controller
recorder *_MockHandlerRecorder
}
// Recorder for MockHandler (not exported)
type _MockHandlerRecorder struct {
mock *MockHandler
}
func NewMockHandler(ctrl *gomock.Controller) *MockHandler {
mock := &MockHandler{ctrl: ctrl}
mock.recorder = &_MockHandlerRecorder{mock}
return mock
}
func (m *MockHandler) EXPECT() *_MockHandlerRecorder {
return m.recorder
}
func (m *MockHandler) Run(_param0 ...interface{}) {
m.ctrl.Call(m, "Run", _param0)
}
func (mr *_MockHandlerRecorder) Run(arg0 ...interface{}) *gomock.Call {
return mr.mock.ctrl.RecordCall(mr.mock, "Run", arg0)
}
func (m *MockHandler) Id() HandlerID {
ret := m.ctrl.Call(m, "Id")
ret0, _ := ret[0].(HandlerID)
return ret0
}
func (mr *_MockHandlerRecorder) Id() *gomock.Call {
return mr.mock.ctrl.RecordCall(mr.mock, "Id")
}
// Mock of EventDispatcher interface
type MockEventDispatcher struct {
ctrl *gomock.Controller
recorder *_MockEventDispatcherRecorder
}
// Recorder for MockEventDispatcher (not exported)
type _MockEventDispatcherRecorder struct {
mock *MockEventDispatcher
}
func NewMockEventDispatcher(ctrl *gomock.Controller) *MockEventDispatcher {
mock := &MockEventDispatcher{ctrl: ctrl}
mock.recorder = &_MockEventDispatcherRecorder{mock}
return mock
}
func (m *MockEventDispatcher) EXPECT() *_MockEventDispatcherRecorder {
return m.recorder
}
func (m *MockEventDispatcher) Dispatch(name string, ev ...interface{}) {
m.ctrl.Call(m, "Dispatch", name, ev)
}
func (mr *_MockEventDispatcherRecorder) Dispatch(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
return mr.mock.ctrl.RecordCall(mr.mock, "Dispatch", arg0, arg1)
}
// Mock of EventRegistry interface
type MockEventRegistry struct {
ctrl *gomock.Controller
recorder *_MockEventRegistryRecorder
}
// Recorder for MockEventRegistry (not exported)
type _MockEventRegistryRecorder struct {
mock *MockEventRegistry
}
func NewMockEventRegistry(ctrl *gomock.Controller) *MockEventRegistry {
mock := &MockEventRegistry{ctrl: ctrl}
mock.recorder = &_MockEventRegistryRecorder{mock}
return mock
}
func (m *MockEventRegistry) EXPECT() *_MockEventRegistryRecorder {
return m.recorder
}
func (m *MockEventRegistry) AddHandler(h Handler, names ...string) {
m.ctrl.Call(m, "AddHandler", h, names)
}
func (mr *_MockEventRegistryRecorder) AddHandler(arg0 interface{}, arg1 ...string) *gomock.Call {
return mr.mock.ctrl.RecordCall(mr.mock, "AddHandler", arg0, arg1)
}
func (m *MockEventRegistry) DelHandler(h Handler, names ...string) {
m.ctrl.Call(m, "DelHandler", h, names)
}
func (mr *_MockEventRegistryRecorder) DelHandler(arg0 interface{}, arg1 ...string) *gomock.Call {
return mr.mock.ctrl.RecordCall(mr.mock, "DelHandler", arg0, arg1)
}
func (m *MockEventRegistry) Dispatch(name string, ev ...interface{}) {
m.ctrl.Call(m, "Dispatch", name, ev)
}
func (mr *_MockEventRegistryRecorder) Dispatch(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
return mr.mock.ctrl.RecordCall(mr.mock, "Dispatch", arg0, arg1)
}
func (m *MockEventRegistry) ClearEvents(name string) {
m.ctrl.Call(m, "ClearEvents", name)
}
func (mr *_MockEventRegistryRecorder) ClearEvents(arg0 interface{}) *gomock.Call {
return mr.mock.ctrl.RecordCall(mr.mock, "ClearEvents", arg0)
}

View File

@ -1,162 +0,0 @@
package event
import (
"container/list"
"strings"
"sync/atomic"
"sync"
)
type HandlerID uint32
var hidCounter uint32 = 0
func NewHandlerID() HandlerID {
return HandlerID(atomic.AddUint32(&hidCounter, 1))
}
type Handler interface {
Run(...interface{})
Id() HandlerID
}
type basicHandler struct {
fn func(...interface{})
id HandlerID
}
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()}
}
type EventDispatcher interface {
Dispatch(name string, ev ...interface{})
}
type EventRegistry interface {
AddHandler(h Handler, names ...string)
DelHandler(h Handler, names ...string)
Dispatch(name string, ev ...interface{})
ClearEvents(name string)
}
type registry struct {
// Event registry as a lockable map of linked-lists
sync.RWMutex
events map[string]*list.List
dispatcher func(r *registry, name string, ev ...interface{})
}
func NewRegistry() *registry {
r := &registry{events: make(map[string]*list.List)}
r.Parallel()
return r
}
func (r *registry) AddHandler(h Handler, names ...string) {
if len(names) == 0 {
return
}
r.Lock()
defer r.Unlock()
N: for _, name := range names {
name = strings.ToLower(name)
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
if e.Value.(Handler).Id() == h.Id() {
continue N
}
}
r.events[name].PushBack(h)
}
}
func _del(l *list.List, id HandlerID) bool {
for e := l.Front(); e != nil; e = e.Next() {
if e.Value.(Handler).Id() == id {
l.Remove(e)
}
}
return l.Len() == 0
}
func (r *registry) DelHandler(h Handler, names ...string) {
r.Lock()
defer r.Unlock()
if len(names) == 0 {
for name, l := range r.events {
if _del(l, h.Id()) {
r.events[name] = nil, false
}
}
} else {
for _, name := range names {
name = strings.ToLower(name)
if l, ok := r.events[name]; ok {
if _del(l, h.Id()) {
r.events[name] = nil, false
}
}
}
}
}
func (r *registry) Dispatch(name string, ev ...interface{}) {
r.dispatcher(r, strings.ToLower(name), ev...)
}
func (r *registry) ClearEvents(name string) {
name = strings.ToLower(name)
r.Lock()
defer r.Unlock()
if l, ok := r.events[name]; ok {
l.Init() // I hope this is enough to GC all list elements.
r.events[name] = nil, false
}
}
func (r *registry) Parallel() {
r.dispatcher = (*registry).parallelDispatch
}
func (r *registry) Serial() {
r.dispatcher = (*registry).serialDispatch
}
func (r *registry) parallelDispatch(name string, ev ...interface{}) {
r.RLock()
defer r.RUnlock()
if l, ok := r.events[name]; ok {
for e := l.Front(); e != nil; e = e.Next() {
h := e.Value.(Handler)
go h.Run(ev...)
}
}
}
func (r *registry) serialDispatch(name string, ev ...interface{}) {
r.RLock()
defer r.RUnlock()
if l, ok := r.events[name]; ok {
hlist := make([]Handler, l.Len())
for e, i := l.Front(), 0; e != nil; e, i = e.Next(), i+1 {
hlist[i] = e.Value.(Handler)
}
go func() {
for _, h := range hlist {
h.Run(ev...)
}
}()
}
}

View File

@ -1,224 +0,0 @@
package event
// oh hey unit tests. or functionality tests, or something.
import (
"testing"
"time"
)
func TestAddDelHandler(t *testing.T) {
r := NewRegistry()
if len(r.events) != 0 {
t.Errorf("New registry has non-zero-length event map.")
}
h1 := NewHandler(func(ev ...interface{}) {})
h2 := NewHandler(func(ev ...interface{}) {})
// Ensure that a handler with no events to handle doesn't get added
r.AddHandler(h1)
if len(r.events) != 0 {
t.Errorf("Adding handler with no events succeded.")
}
// Add h1 to a couple of events.
r.AddHandler(h1, "e1", "E2")
if len(r.events) != 2 {
t.Errorf("Adding handler h1 to events failed.")
}
if l, ok := r.events["e1"]; !ok || l.Len() != 1 ||
l.Front().Value != h1 {
t.Errorf("Handler h1 not added to event e1 correctly.")
}
if l, ok := r.events["e2"]; !ok || l.Len() != 1 ||
l.Front().Value != h1 {
t.Errorf("Handler h1 not added to event e2 correctly.")
}
// Add h2 to a couple of events.
r.AddHandler(h2, "e2", "E3")
if len(r.events) != 3 {
t.Errorf("Adding handler h2 to events failed.")
}
if l, ok := r.events["e2"]; !ok || l.Len() != 2 ||
l.Front().Next().Value.(Handler) != h2 {
t.Errorf("Handler h2 not added to event e2 correctly.")
}
if l, ok := r.events["e3"]; !ok || l.Len() != 1 ||
l.Front().Value.(Handler) != h2 {
t.Errorf("Handler h2 not added to event e3 correctly.")
}
// Add h1 to some more events, which it may be in already.
r.AddHandler(h1, "e2", "e3", "e4", "e5")
if len(r.events) != 5 {
t.Errorf("Adding handler h1 to more events failed.")
println(len(r.events))
}
if l, ok := r.events["e2"]; !ok || l.Len() != 2 {
t.Errorf("Handler h1 added twice to event e2.")
}
if l, ok := r.events["e3"]; !ok || l.Len() != 2 ||
l.Front().Next().Value.(Handler) != h1 {
t.Errorf("Handler h1 not added to event e3 correctly.")
}
// Add h2 to a few more events, for testing delete
r.AddHandler(h2, "e5", "e6")
if len(r.events) != 6 {
t.Errorf("Adding handler h2 to more events failed.")
}
// Currently, we have the following handlers set up:
// h1: e1 e2 e3 e4 e5
// h2: e2 e3 e5 e6
// NOTE: for e3, h2 is first and h1 is second in the linked list
// Delete h1 from a few events. This should remove e4 completely.
r.DelHandler(h1, "e2", "E3", "e4")
if _, ok := r.events["e4"]; ok || len(r.events) != 5 {
t.Errorf("Deleting h1 from some events failed to remove e4.")
}
if l, ok := r.events["e2"]; !ok || l.Len() != 1 ||
l.Front().Value.(Handler) != h2 {
t.Errorf("Handler h1 not deleted from event e2 correctly.")
}
if l, ok := r.events["e3"]; !ok || l.Len() != 1 ||
l.Front().Value.(Handler) != h2 {
t.Errorf("Handler h1 not deleted from event e3 correctly.")
}
// Now, we have the following handlers set up:
// h1: e1 e5
// h2: e2 e3 e5 e6
// Delete h2 from a couple of events, removing e2 and e3.
// Deleting h2 from a handler it is not in should not cause problems.
r.DelHandler(h2, "e1", "e2", "e3")
if len(r.events) != 3 {
t.Errorf("Deleting h2 from some events failed to remove e{2,3}.")
}
if l, ok := r.events["e1"]; !ok || l.Len() != 1 ||
l.Front().Value.(Handler) != h1 {
t.Errorf("Handler h1 deleted from event e1 incorrectly.")
}
// Delete h1 completely.
r.DelHandler(h1)
if _, ok := r.events["e1"]; ok || len(r.events) != 2 {
t.Errorf("Deleting h1 completely failed to remove e1.")
}
if l, ok := r.events["e5"]; !ok || l.Len() != 1 ||
l.Front().Value.(Handler) != h2 {
t.Errorf("Handler h1 deleted from event e5 incorrectly.")
}
// Clear e5 completely
r.ClearEvents("e5")
if _, ok := r.events["e5"]; ok || len(r.events) != 1 {
t.Errorf("Deleting e5 completely failed to remove it.")
}
// All that should be left is e6, with h2 as it's only handler.
if l, ok := r.events["e6"]; !ok || l.Len() != 1 ||
l.Front().Value.(Handler) != h2 {
t.Errorf("Remaining event and handler doesn't match expectations.")
}
}
func TestSimpleDispatch(t *testing.T) {
r := NewRegistry()
out := make(chan bool)
h := NewHandler(func(ev ...interface{}) {
out <- ev[0].(bool)
})
r.AddHandler(h, "send")
r.Dispatch("send", true)
if val := <-out; !val {
t.Fail()
}
r.Dispatch("send", false)
if val := <-out; val {
t.Fail()
}
}
func TestParallelDispatch(t *testing.T) {
r := NewRegistry()
// ensure we have enough of a buffer that all sends complete
out := make(chan int, 5)
// handler factory :-)
factory := func(t int) Handler {
return NewHandler(func(ev ...interface{}) {
// t * 10ms sleep
time.Sleep(int64(t * 1e7))
out <- t
})
}
// create some handlers and send an event to them
for _, t := range []int{5, 11, 2, 15, 8} {
r.AddHandler(factory(t), "send")
}
r.Dispatch("send")
// If parallel dispatch is working, results from out should be in numerical order
if val := <-out; val != 2 {
t.Fail()
}
if val := <-out; val != 5 {
t.Fail()
}
if val := <-out; val != 8 {
t.Fail()
}
if val := <-out; val != 11 {
t.Fail()
}
if val := <-out; val != 15 {
t.Fail()
}
}
func TestSerialDispatch(t *testing.T) {
r := NewRegistry()
r.Serial()
// ensure we have enough of a buffer that all sends complete
out := make(chan int, 5)
// handler factory :-)
factory := func(t int) Handler {
return NewHandler(func(ev ...interface{}) {
// t * 10ms sleep
time.Sleep(int64(t * 1e7))
out <- t
})
}
// create some handlers and send an event to them
for _, t := range []int{5, 11, 2, 15, 8} {
r.AddHandler(factory(t), "send")
}
r.Dispatch("send")
// If serial dispatch is working, results from out should be in handler order
if val := <-out; val != 5 {
t.Fail()
}
if val := <-out; val != 11 {
t.Fail()
}
if val := <-out; val != 2 {
t.Fail()
}
if val := <-out; val != 15 {
t.Fail()
}
if val := <-out; val != 8 {
t.Fail()
}
}