diff --git a/irc_callback.go b/irc_callback.go index 3035f3a..0630f65 100644 --- a/irc_callback.go +++ b/irc_callback.go @@ -4,30 +4,63 @@ import ( "strconv" "strings" "time" + "crypto/sha1" + "fmt" + "reflect" + "math/rand" ) -func (irc *Connection) AddCallback(eventcode string, callback func(*Event)) { +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) - - } else { - irc.events[eventcode] = make([]func(*Event), 1) - irc.events[eventcode][0] = callback + if _, ok := irc.events[eventcode]; !ok { + irc.events[eventcode] = make(map[string]func(*Event)) } + 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) ReplaceCallback(eventcode string, i int, callback func(*Event)) { +func (irc *Connection) RemoveCallback(eventcode string, i string) bool { + eventcode = strings.ToUpper(eventcode) + + 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 id %s\n", i) + return false + } + + irc.Log.Println("Event not found") + 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) 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") } @@ -71,14 +104,23 @@ 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() { - 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 fa872ba..57a4443 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..da514fa 100644 --- a/irc_test.go +++ b/irc_test.go @@ -44,3 +44,79 @@ 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") + } +} + +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