From 33d801979353f4949b04dd42e8b0b8a47ca2a985 Mon Sep 17 00:00:00 2001 From: Andrew Montgomery-Hurrell Date: Mon, 10 Feb 2014 22:20:18 +0000 Subject: [PATCH 1/3] Added ability to get the index of a callback in the callback registry. Ability to process events against a 'wildcard' handler --- irc_callback.go | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/irc_callback.go b/irc_callback.go index 6560c36..0e4c87b 100644 --- a/irc_callback.go +++ b/irc_callback.go @@ -6,16 +6,32 @@ import ( "time" ) -func (irc *Connection) AddCallback(eventcode string, callback func(*Event)) { +func (irc *Connection) AddCallback(eventcode string, callback func(*Event)) (idx int) { eventcode = strings.ToUpper(eventcode) if _, ok := irc.events[eventcode]; ok { irc.events[eventcode] = append(irc.events[eventcode], callback) - + idx = len(irc.events[eventcode]) - 1 } else { irc.events[eventcode] = make([]func(*Event), 1) irc.events[eventcode][0] = callback + idx = 0 } + return +} + +func (irc *Connection) RemoveCallback(eventcode string, i int) { + eventcode = strings.ToUpper(eventcode) + + if event, ok := irc.events[eventcode]; ok { + if i < len(event) { + irc.events[eventcode] = append(event[:i], event[i+1:]...) + return + } + irc.Log.Printf("Event found, but no callback found at index %d.\n", i) + return + } + irc.Log.Printf("Event not found\n") } func (irc *Connection) ReplaceCallback(eventcode string, i int, callback func(*Event)) { @@ -70,10 +86,19 @@ func (irc *Connection) RunCallbacks(event *Event) { for _, callback := range callbacks { go callback(event) } - } else if irc.VerboseCallbackHandler { irc.Log.Printf("%v (0) >> %#v\n", event.Code, event) } + + if callbacks, ok := irc.events["*"]; ok { + if irc.VerboseCallbackHandler { + irc.Log.Printf("Wildcard %v (%v) >> %#v\n", event.Code, len(callbacks), event) + } + + for _, callback := range callbacks { + go callback(event) + } + } } func (irc *Connection) setupCallbacks() { From 6edb7ec06ee4901b710eed56963180705ee8b306 Mon Sep 17 00:00:00 2001 From: Andrew Montgomery-Hurrell Date: Tue, 11 Feb 2014 23:35:13 +0000 Subject: [PATCH 2/3] Added unique id to callbacks so they can be referenced. Since Go doens't actually provide unique function pointers, we use the closest we can get by grabbing the pointer for the function and slapping a random int on the end. Does it guarantee there will never be a collision? No, but it makes it's pretty damn unlikely that you'll get one during the lifetime of an app unless you are generating millions and millions of callbacks and never, ever deleting them, in which case you probably have something else to worry about --- irc_callback.go | 49 ++++++++++++++++++++++++++---------------------- irc_struct.go | 2 +- irc_test.go | 50 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 23 deletions(-) diff --git a/irc_callback.go b/irc_callback.go index 0e4c87b..fd74fa2 100644 --- a/irc_callback.go +++ b/irc_callback.go @@ -4,46 +4,51 @@ import ( "strconv" "strings" "time" + "crypto/sha1" + "fmt" + "reflect" + "math/rand" ) -func (irc *Connection) AddCallback(eventcode string, callback func(*Event)) (idx int) { +func (irc *Connection) AddCallback(eventcode string, callback func(*Event)) string { eventcode = strings.ToUpper(eventcode) - if _, ok := irc.events[eventcode]; ok { - irc.events[eventcode] = append(irc.events[eventcode], callback) - idx = len(irc.events[eventcode]) - 1 - } else { - irc.events[eventcode] = make([]func(*Event), 1) - irc.events[eventcode][0] = callback - idx = 0 + if _, ok := irc.events[eventcode]; !ok { + irc.events[eventcode] = make(map[string]func(*Event)) } - return + h := sha1.New() + rawId := []byte(fmt.Sprintf("%v%d", reflect.ValueOf(callback).Pointer(), rand.Int63())) + h.Write(rawId) + id := fmt.Sprintf("%x", h.Sum(nil)) + irc.events[eventcode][id] = callback + return id } -func (irc *Connection) RemoveCallback(eventcode string, i int) { +func (irc *Connection) RemoveCallback(eventcode string, i string) bool { eventcode = strings.ToUpper(eventcode) - if event, ok := irc.events[eventcode]; ok { - if i < len(event) { - irc.events[eventcode] = append(event[:i], event[i+1:]...) - return + if event, ok := irc.events[eventcode]; ok{ + if _, ok := event[i]; ok { + delete(irc.events[eventcode], i) + return true } - irc.Log.Printf("Event found, but no callback found at index %d.\n", i) - return + irc.Log.Printf("Event found, but no callback found at id %s\n", i) + return false } - irc.Log.Printf("Event not found\n") + + irc.Log.Println("Event not found") + return false } -func (irc *Connection) ReplaceCallback(eventcode string, i int, callback func(*Event)) { +func (irc *Connection) ReplaceCallback(eventcode string, i string, callback func(*Event)) { eventcode = strings.ToUpper(eventcode) if event, ok := irc.events[eventcode]; ok { - if i < len(event) { + if _, ok := event[i]; ok { event[i] = callback return } - irc.Log.Printf("Event found, but no callback found at index %d. Use AddCallback\n", i) - return + irc.Log.Printf("Event found, but no callback found at id %s\n", i) } irc.Log.Printf("Event not found. Use AddCallBack\n") } @@ -102,7 +107,7 @@ func (irc *Connection) RunCallbacks(event *Event) { } func (irc *Connection) setupCallbacks() { - irc.events = make(map[string][]func(*Event)) + irc.events = make(map[string]map[string]func(*Event)) //Handle ping events irc.AddCallback("PING", func(e *Event) { irc.SendRaw("PONG :" + e.Message) }) diff --git a/irc_struct.go b/irc_struct.go index f3c1883..964928e 100644 --- a/irc_struct.go +++ b/irc_struct.go @@ -33,7 +33,7 @@ type Connection struct { user string registered bool server string - events map[string][]func(*Event) + events map[string]map[string]func(*Event) lastMessage time.Time diff --git a/irc_test.go b/irc_test.go index c91f8ab..9938c3d 100644 --- a/irc_test.go +++ b/irc_test.go @@ -44,3 +44,53 @@ func TestConnectionSSL(t *testing.T) { irccon.Loop() } + +func TestRemoveCallback(t *testing.T) { + irccon := IRC("go-eventirc", "go-eventirc") + irccon.VerboseCallbackHandler = true + + done := make(chan int, 10) + + irccon.AddCallback("TEST", func(e *Event) { done <- 1 }) + id := irccon.AddCallback("TEST", func(e *Event) { done <- 2 }) + irccon.AddCallback("TEST", func(e *Event) { done <- 3 }) + + // Should remove callback at index 1 + irccon.RemoveCallback("TEST", id) + + irccon.RunCallbacks(&Event{ + Code: "TEST", + }) + + var results []int + + results = append(results, <-done) + results = append(results, <-done) + + if len(results) != 2 || !(results[0] == 1 && results[1] == 3) { + t.Error("Callback 2 not removed") + } +} + +func TestWildcardCallback(t *testing.T) { + irccon := IRC("go-eventirc", "go-eventirc") + irccon.VerboseCallbackHandler = true + + done := make(chan int, 10) + + irccon.AddCallback("TEST", func(e *Event) { done <- 1 }) + irccon.AddCallback("*", func(e *Event) { done <- 2 }) + + irccon.RunCallbacks(&Event{ + Code: "TEST", + }) + + var results []int + + results = append(results, <-done) + results = append(results, <-done) + + if len(results) != 2 || !(results[0] == 1 && results[1] == 2) { + t.Error("Wildcard callback not called") + } +} From bf01c6c9e2b5133df9335aef7902e2c90e058303 Mon Sep 17 00:00:00 2001 From: Andrew Montgomery-Hurrell Date: Tue, 11 Feb 2014 23:57:08 +0000 Subject: [PATCH 3/3] Added ClearCallback method for clearing all callbacks for an event --- irc_callback.go | 12 ++++++++++++ irc_test.go | 26 ++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/irc_callback.go b/irc_callback.go index fd74fa2..cb8498c 100644 --- a/irc_callback.go +++ b/irc_callback.go @@ -40,6 +40,18 @@ func (irc *Connection) RemoveCallback(eventcode string, i string) bool { return false } +func (irc *Connection) ClearCallback(eventcode string) bool { + eventcode = strings.ToUpper(eventcode) + + if _, ok := irc.events[eventcode]; ok{ + irc.events[eventcode] = make(map[string]func(*Event)) + return true + } + + irc.Log.Println("Event not found") + return false +} + func (irc *Connection) ReplaceCallback(eventcode string, i string, callback func(*Event)) { eventcode = strings.ToUpper(eventcode) diff --git a/irc_test.go b/irc_test.go index 9938c3d..da514fa 100644 --- a/irc_test.go +++ b/irc_test.go @@ -94,3 +94,29 @@ func TestWildcardCallback(t *testing.T) { t.Error("Wildcard callback not called") } } + +func TestClearCallback(t *testing.T) { + irccon := IRC("go-eventirc", "go-eventirc") + irccon.VerboseCallbackHandler = true + + done := make(chan int, 10) + + irccon.AddCallback("TEST", func(e *Event) { done <- 0 }) + irccon.AddCallback("TEST", func(e *Event) { done <- 1 }) + irccon.ClearCallback("TEST") + irccon.AddCallback("TEST", func(e *Event) { done <- 2 }) + irccon.AddCallback("TEST", func(e *Event) { done <- 3 }) + + irccon.RunCallbacks(&Event{ + Code: "TEST", + }) + + var results []int + + results = append(results, <-done) + results = append(results, <-done) + + if len(results) != 2 || !(results[0] == 2 && results[1] == 3) { + t.Error("Callbacks not cleared") + } +} \ No newline at end of file