From da78ed515c0f0833e7a92c7cc52898176198e2c1 Mon Sep 17 00:00:00 2001 From: Thomas Jager Date: Sat, 6 Feb 2016 21:33:04 +0100 Subject: [PATCH] BREAKING CHANGES: Run callbacks in main thread and int callback id. Execute callbacks in main thread. This will break callbacks that use a long time to execute. Create your own thread in AddCallback using gorutines on long running callbacks. Use deterministic IDs for AddCallback. Changes the id from SHA-hash to int. --- README.markdown | 14 ++++++++++++ irc_callback.go | 40 +++++++++++++-------------------- irc_struct.go | 2 +- irc_test.go | 60 +++++++++++++++++++++++++++---------------------- 4 files changed, 64 insertions(+), 52 deletions(-) diff --git a/README.markdown b/README.markdown index 3b4eefb..2b3524b 100644 --- a/README.markdown +++ b/README.markdown @@ -46,6 +46,20 @@ AddCallback Example //event.Arguments[0] Contains the channel }); +Please note: Callbacks are run in the main thread. If a callback needs a long +time to execute please run it in a new thread. + +Example: + + ircobj.AddCallback("PRIVMSG", func(event *irc.Event) { + go func(event *irc.Event) { + //event.Message() contains the message + //event.Nick Contains the sender + //event.Arguments[0] Contains the channel + }(e) + }); + + Commands -------- ircobj := irc.IRC("", "") //Create new ircobj diff --git a/irc_callback.go b/irc_callback.go index fad0d11..109cbb1 100644 --- a/irc_callback.go +++ b/irc_callback.go @@ -1,10 +1,6 @@ package irc import ( - "crypto/sha1" - "fmt" - "math/rand" - "reflect" "strconv" "strings" "time" @@ -14,23 +10,22 @@ import ( // which takes only an Event pointer as parameter. Valid event codes are all // IRC/CTCP commands and error/response codes. This function returns the ID of // the registered callback for later management. -func (irc *Connection) AddCallback(eventcode string, callback func(*Event)) string { +func (irc *Connection) AddCallback(eventcode string, callback func(*Event)) int { eventcode = strings.ToUpper(eventcode) - + id := 0 if _, ok := irc.events[eventcode]; !ok { - irc.events[eventcode] = make(map[string]func(*Event)) + irc.events[eventcode] = make(map[int]func(*Event)) + id = 0 + } else { + id = len(irc.events[eventcode]) } - 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 } // Remove callback i (ID) from the given event code. This functions returns // true upon success, false if any error occurs. -func (irc *Connection) RemoveCallback(eventcode string, i string) bool { +func (irc *Connection) RemoveCallback(eventcode string, i int) bool { eventcode = strings.ToUpper(eventcode) if event, ok := irc.events[eventcode]; ok { @@ -52,7 +47,7 @@ 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)) + irc.events[eventcode] = make(map[int]func(*Event)) return true } @@ -61,7 +56,7 @@ func (irc *Connection) ClearCallback(eventcode string) bool { } // Replace callback i (ID) associated with a given event code with a new callback function. -func (irc *Connection) ReplaceCallback(eventcode string, i string, callback func(*Event)) { +func (irc *Connection) ReplaceCallback(eventcode string, i int, callback func(*Event)) { eventcode = strings.ToUpper(eventcode) if event, ok := irc.events[eventcode]; ok { @@ -120,7 +115,7 @@ func (irc *Connection) RunCallbacks(event *Event) { } for _, callback := range callbacks { - go callback(event) + callback(event) } } else if irc.VerboseCallbackHandler { irc.Log.Printf("%v (0) >> %#v\n", event.Code, event) @@ -128,21 +123,22 @@ func (irc *Connection) RunCallbacks(event *Event) { if callbacks, ok := irc.events["*"]; ok { if irc.VerboseCallbackHandler { - irc.Log.Printf("Wildcard %v (%v) >> %#v\n", event.Code, len(callbacks), event) + irc.Log.Printf("%v (0) >> %#v\n", event.Code, event) } for _, callback := range callbacks { - go callback(event) + callback(event) } } } // Set up some initial callbacks to handle the IRC/CTCP protocol. func (irc *Connection) setupCallbacks() { - irc.events = make(map[string]map[string]func(*Event)) + irc.events = make(map[string]map[int]func(*Event)) - //Handle error events - irc.AddCallback("ERROR", func(e *Event) { irc.Disconnect() }) + //Handle error events. This has to be called in a new thred to allow + //readLoop to exit + irc.AddCallback("ERROR", func(e *Event) { go irc.Disconnect() }) //Handle ping events irc.AddCallback("PING", func(e *Event) { irc.SendRaw("PONG :" + e.Message()) }) @@ -223,7 +219,3 @@ func (irc *Connection) setupCallbacks() { irc.nickcurrent = e.Arguments[0] }) } - -func init() { - rand.Seed(time.Now().UnixNano()) -} diff --git a/irc_struct.go b/irc_struct.go index fb301a1..3e4a438 100644 --- a/irc_struct.go +++ b/irc_struct.go @@ -33,7 +33,7 @@ type Connection struct { nickcurrent string //The nickname we currently have. user string registered bool - events map[string]map[string]func(*Event) + events map[string]map[int]func(*Event) QuitMessage string lastMessage time.Time diff --git a/irc_test.go b/irc_test.go index 7b9d856..50bdb68 100644 --- a/irc_test.go +++ b/irc_test.go @@ -184,33 +184,26 @@ func TestConnection(t *testing.T) { irccon2 := IRC("go-eventirc2", "go-eventirc2") irccon2.VerboseCallbackHandler = true irccon2.Debug = true - err := irccon1.Connect("irc.freenode.net:6667") - if err != nil { - t.Log(err.Error()) - t.Fatal("Can't connect to freenode.") - } - err = irccon2.Connect("irc.freenode.net:6667") - if err != nil { - t.Log(err.Error()) - t.Fatal("Can't connect to freenode.") - } + irccon1.AddCallback("001", func(e *Event) { irccon1.Join("#go-eventirc") }) irccon2.AddCallback("001", func(e *Event) { irccon2.Join("#go-eventirc") }) con2ok := false irccon1.AddCallback("366", func(e *Event) { - t := time.NewTicker(1 * time.Second) - i := 10 - for { - <-t.C - irccon1.Privmsgf("#go-eventirc", "Test Message%d\n", i) - if con2ok { - i -= 1 + go func(e *Event) { + t := time.NewTicker(1 * time.Second) + i := 10 + for { + <-t.C + irccon1.Privmsgf("#go-eventirc", "Test Message%d\n", i) + if con2ok { + i -= 1 + } + if i == 0 { + t.Stop() + irccon1.Quit() + } } - if i == 0 { - t.Stop() - irccon1.Quit() - } - } + }(e) }) irccon2.AddCallback("366", func(e *Event) { @@ -231,6 +224,18 @@ func TestConnection(t *testing.T) { t.Fatal("Nick change did not work!") } }) + + err := irccon1.Connect("irc.freenode.net:6667") + if err != nil { + t.Log(err.Error()) + t.Fatal("Can't connect to freenode.") + } + err = irccon2.Connect("irc.freenode.net:6667") + if err != nil { + t.Log(err.Error()) + t.Fatal("Can't connect to freenode.") + } + go irccon2.Loop() irccon1.Loop() } @@ -241,11 +246,6 @@ func TestConnectionSSL(t *testing.T) { irccon.Debug = true irccon.UseTLS = true irccon.TLSConfig = &tls.Config{InsecureSkipVerify: true} - err := irccon.Connect("irc.freenode.net:7000") - if err != nil { - t.Log(err.Error()) - t.Fatal("Can't connect to freenode.") - } irccon.AddCallback("001", func(e *Event) { irccon.Join("#go-eventirc") }) irccon.AddCallback("366", func(e *Event) { @@ -254,5 +254,11 @@ func TestConnectionSSL(t *testing.T) { irccon.Quit() }) + err := irccon.Connect("irc.freenode.net:7000") + if err != nil { + t.Log(err.Error()) + t.Fatal("Can't connect to freenode.") + } + irccon.Loop() }