Callbacks -> Handlers

This commit is contained in:
Liam Stanley 2017-02-11 22:51:05 -05:00
parent c9243b15b3
commit 69a6d77ac8
5 changed files with 144 additions and 145 deletions

@ -9,67 +9,67 @@ import (
"time" "time"
) )
// registerHandlers sets up built-in callbacks/helpers, based on client // registerBuiltin sets up built-in handlers, based on client
// configuration. // configuration.
func (c *Client) registerHandlers() { func (c *Client) registerBuiltin() {
c.debug.Print("registering built-in handlers") c.debug.Print("registering built-in handlers")
c.Callbacks.mu.Lock() c.Handlers.mu.Lock()
// Built-in things that should always be supported. // Built-in things that should always be supported.
c.Callbacks.register(true, RPL_WELCOME, CallbackFunc(func(c *Client, e Event) { c.Handlers.register(true, RPL_WELCOME, HandlerFunc(func(c *Client, e Event) {
go handleConnect(c, e) go handleConnect(c, e)
})) }))
c.Callbacks.register(true, PING, CallbackFunc(handlePING)) c.Handlers.register(true, PING, HandlerFunc(handlePING))
if !c.Config.disableTracking { if !c.Config.disableTracking {
// Joins/parts/anything that may add/remove/rename users. // Joins/parts/anything that may add/remove/rename users.
c.Callbacks.register(true, JOIN, CallbackFunc(handleJOIN)) c.Handlers.register(true, JOIN, HandlerFunc(handleJOIN))
c.Callbacks.register(true, PART, CallbackFunc(handlePART)) c.Handlers.register(true, PART, HandlerFunc(handlePART))
c.Callbacks.register(true, KICK, CallbackFunc(handleKICK)) c.Handlers.register(true, KICK, HandlerFunc(handleKICK))
c.Callbacks.register(true, QUIT, CallbackFunc(handleQUIT)) c.Handlers.register(true, QUIT, HandlerFunc(handleQUIT))
c.Callbacks.register(true, NICK, CallbackFunc(handleNICK)) c.Handlers.register(true, NICK, HandlerFunc(handleNICK))
c.Callbacks.register(true, RPL_NAMREPLY, CallbackFunc(handleNAMES)) c.Handlers.register(true, RPL_NAMREPLY, HandlerFunc(handleNAMES))
// Modes. // Modes.
c.Callbacks.register(true, MODE, CallbackFunc(handleMODE)) c.Handlers.register(true, MODE, HandlerFunc(handleMODE))
c.Callbacks.register(true, RPL_CHANNELMODEIS, CallbackFunc(handleMODE)) c.Handlers.register(true, RPL_CHANNELMODEIS, HandlerFunc(handleMODE))
// WHO/WHOX responses. // WHO/WHOX responses.
c.Callbacks.register(true, RPL_WHOREPLY, CallbackFunc(handleWHO)) c.Handlers.register(true, RPL_WHOREPLY, HandlerFunc(handleWHO))
c.Callbacks.register(true, RPL_WHOSPCRPL, CallbackFunc(handleWHO)) c.Handlers.register(true, RPL_WHOSPCRPL, HandlerFunc(handleWHO))
// Other misc. useful stuff. // Other misc. useful stuff.
c.Callbacks.register(true, TOPIC, CallbackFunc(handleTOPIC)) c.Handlers.register(true, TOPIC, HandlerFunc(handleTOPIC))
c.Callbacks.register(true, RPL_TOPIC, CallbackFunc(handleTOPIC)) c.Handlers.register(true, RPL_TOPIC, HandlerFunc(handleTOPIC))
c.Callbacks.register(true, RPL_MYINFO, CallbackFunc(handleMYINFO)) c.Handlers.register(true, RPL_MYINFO, HandlerFunc(handleMYINFO))
c.Callbacks.register(true, RPL_ISUPPORT, CallbackFunc(handleISUPPORT)) c.Handlers.register(true, RPL_ISUPPORT, HandlerFunc(handleISUPPORT))
c.Callbacks.register(true, RPL_MOTDSTART, CallbackFunc(handleMOTD)) c.Handlers.register(true, RPL_MOTDSTART, HandlerFunc(handleMOTD))
c.Callbacks.register(true, RPL_MOTD, CallbackFunc(handleMOTD)) c.Handlers.register(true, RPL_MOTD, HandlerFunc(handleMOTD))
// Keep users lastactive times up to date. // Keep users lastactive times up to date.
c.Callbacks.register(true, PRIVMSG, CallbackFunc(updateLastActive)) c.Handlers.register(true, PRIVMSG, HandlerFunc(updateLastActive))
c.Callbacks.register(true, NOTICE, CallbackFunc(updateLastActive)) c.Handlers.register(true, NOTICE, HandlerFunc(updateLastActive))
c.Callbacks.register(true, TOPIC, CallbackFunc(updateLastActive)) c.Handlers.register(true, TOPIC, HandlerFunc(updateLastActive))
c.Callbacks.register(true, KICK, CallbackFunc(updateLastActive)) c.Handlers.register(true, KICK, HandlerFunc(updateLastActive))
// CAP IRCv3-specific tracking and functionality. // CAP IRCv3-specific tracking and functionality.
if !c.Config.disableCapTracking { if !c.Config.disableCapTracking {
c.Callbacks.register(true, CAP, CallbackFunc(handleCAP)) c.Handlers.register(true, CAP, HandlerFunc(handleCAP))
c.Callbacks.register(true, CAP_CHGHOST, CallbackFunc(handleCHGHOST)) c.Handlers.register(true, CAP_CHGHOST, HandlerFunc(handleCHGHOST))
c.Callbacks.register(true, CAP_AWAY, CallbackFunc(handleAWAY)) c.Handlers.register(true, CAP_AWAY, HandlerFunc(handleAWAY))
c.Callbacks.register(true, CAP_ACCOUNT, CallbackFunc(handleACCOUNT)) c.Handlers.register(true, CAP_ACCOUNT, HandlerFunc(handleACCOUNT))
c.Callbacks.register(true, ALLEVENTS, CallbackFunc(handleTags)) c.Handlers.register(true, ALLEVENTS, HandlerFunc(handleTags))
} }
} }
// Nickname collisions. // Nickname collisions.
if !c.Config.disableNickCollision { if !c.Config.disableNickCollision {
c.Callbacks.register(true, ERR_NICKNAMEINUSE, CallbackFunc(nickCollisionHandler)) c.Handlers.register(true, ERR_NICKNAMEINUSE, HandlerFunc(nickCollisionHandler))
c.Callbacks.register(true, ERR_NICKCOLLISION, CallbackFunc(nickCollisionHandler)) c.Handlers.register(true, ERR_NICKCOLLISION, HandlerFunc(nickCollisionHandler))
c.Callbacks.register(true, ERR_UNAVAILRESOURCE, CallbackFunc(nickCollisionHandler)) c.Handlers.register(true, ERR_UNAVAILRESOURCE, HandlerFunc(nickCollisionHandler))
} }
c.Callbacks.mu.Unlock() c.Handlers.mu.Unlock()
} }
// handleConnect is a helper function which lets the client know that enough // handleConnect is a helper function which lets the client know that enough
@ -286,7 +286,7 @@ func handleMYINFO(c *Client, e Event) {
// For example, things like max channel name length, or nickname length. // For example, things like max channel name length, or nickname length.
func handleISUPPORT(c *Client, e Event) { func handleISUPPORT(c *Client, e Event) {
// Must be a ISUPPORT-based message. 005 is also used for server bounce // Must be a ISUPPORT-based message. 005 is also used for server bounce
// related things, so this callback may be triggered during other // related things, so this handler may be triggered during other
// situations. // situations.
// Also known as RPL_PROTOCTL. // Also known as RPL_PROTOCTL.

167
caller.go

@ -13,8 +13,8 @@ import (
"time" "time"
) )
// RunCallbacks manually runs callbacks for a given event. // RunHandlers manually runs handlers for a given event.
func (c *Client) RunCallbacks(event *Event) { func (c *Client) RunHandlers(event *Event) {
if event == nil { if event == nil {
return return
} }
@ -22,11 +22,11 @@ func (c *Client) RunCallbacks(event *Event) {
// Log the event. // Log the event.
c.debug.Print("< " + StripRaw(event.String())) c.debug.Print("< " + StripRaw(event.String()))
// Regular wildcard callbacks. // Regular wildcard handlers.
c.Callbacks.exec(ALLEVENTS, c, event.Copy()) c.Handlers.exec(ALLEVENTS, c, event.Copy())
// Then regular callbacks. // Then regular handlers.
c.Callbacks.exec(event.Command, c, event.Copy()) c.Handlers.exec(event.Command, c, event.Copy())
// Check if it's a CTCP. // Check if it's a CTCP.
if ctcp := decodeCTCP(event.Copy()); ctcp != nil { if ctcp := decodeCTCP(event.Copy()); ctcp != nil {
@ -35,52 +35,52 @@ func (c *Client) RunCallbacks(event *Event) {
} }
} }
// Callback is lower level implementation of a callback. See // Handler is lower level implementation of a handler. See
// Caller.AddHandler() // Caller.AddHandler()
type Callback interface { type Handler interface {
Execute(*Client, Event) Execute(*Client, Event)
} }
// CallbackFunc is a type that represents the function necessary to // HandlerFunc is a type that represents the function necessary to
// implement Callback. // implement Handler.
type CallbackFunc func(c *Client, e Event) type HandlerFunc func(c *Client, e Event)
// Execute calls the CallbackFunc with the sender and irc message. // Execute calls the HandlerFunc with the sender and irc message.
func (f CallbackFunc) Execute(c *Client, e Event) { func (f HandlerFunc) Execute(c *Client, e Event) {
f(c, e) f(c, e)
} }
// Caller manages internal and external (user facing) callbacks. // Caller manages internal and external (user facing) handlers.
//
// external/internal keys are of structure:
// map[COMMAND][CUID]Callback
//
// Also of note: "COMMAND" should always be uppercase for normalization.
type Caller struct { type Caller struct {
// mu is the mutex that should be used when accessing callbacks. // mu is the mutex that should be used when accessing handlers.
mu sync.RWMutex mu sync.RWMutex
// wg is the waitgroup which is used to execute all callbacks concurrently. // wg is the waitgroup which is used to execute all handlers concurrently.
wg sync.WaitGroup wg sync.WaitGroup
// external is a map of user facing callbacks.
external map[string]map[string]Callback // external/internal keys are of structure:
// internal is a map of internally used callbacks for the client. // map[COMMAND][CUID]Handler
internal map[string]map[string]Callback // Also of note: "COMMAND" should always be uppercase for normalization.
// external is a map of user facing handlers.
external map[string]map[string]Handler
// internal is a map of internally used handlers for the client.
internal map[string]map[string]Handler
// debug is the clients logger used for debugging. // debug is the clients logger used for debugging.
debug *log.Logger debug *log.Logger
} }
// newCaller creates and initializes a new callback handler. // newCaller creates and initializes a new handler.
func newCaller(debugger *log.Logger) *Caller { func newCaller(debugger *log.Logger) *Caller {
c := &Caller{ c := &Caller{
external: map[string]map[string]Callback{}, external: map[string]map[string]Handler{},
internal: map[string]map[string]Callback{}, internal: map[string]map[string]Handler{},
debug: debugger, debug: debugger,
} }
return c return c
} }
// Len returns the total amount of user-entered registered callbacks. // Len returns the total amount of user-entered registered handlers.
func (c *Caller) Len() int { func (c *Caller) Len() int {
var total int var total int
@ -94,7 +94,7 @@ func (c *Caller) Len() int {
} }
// Count is much like Caller.Len(), however it counts the number of // Count is much like Caller.Len(), however it counts the number of
// registered callbacks for a given command. // registered handlers for a given command.
func (c *Caller) Count(cmd string) int { func (c *Caller) Count(cmd string) int {
var total int var total int
@ -125,7 +125,7 @@ func (c *Caller) String() string {
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
// cuid generates a unique UID string for each callback for ease of removal. // cuid generates a unique UID string for each handler for ease of removal.
func (c *Caller) cuid(cmd string, n int) (cuid, uid string) { func (c *Caller) cuid(cmd string, n int) (cuid, uid string) {
b := make([]byte, n) b := make([]byte, n)
@ -137,7 +137,7 @@ func (c *Caller) cuid(cmd string, n int) (cuid, uid string) {
} }
// cuidToID allows easy mapping between a generated cuid and the caller // cuidToID allows easy mapping between a generated cuid and the caller
// external/internal callback maps. // external/internal handler maps.
func (c *Caller) cuidToID(input string) (cmd, uid string) { func (c *Caller) cuidToID(input string) (cmd, uid string) {
// Ignore the errors because the strings will default to empty anyway. // Ignore the errors because the strings will default to empty anyway.
_, _ = fmt.Sscanf(input, "%s:%s", &cmd, &uid) _, _ = fmt.Sscanf(input, "%s:%s", &cmd, &uid)
@ -145,29 +145,28 @@ func (c *Caller) cuidToID(input string) (cmd, uid string) {
} }
type execStack struct { type execStack struct {
Callback Callback Handler
cuid string cuid string
} }
// exec executes all callbacks pertaining to specified event. Internal first, // exec executes all handlers pertaining to specified event. Internal first,
// then external. // then external.
// //
// Please note that there is no specific order/priority for which the // Please note that there is no specific order/priority for which the
// callback types themselves or the callbacks are executed. // handler types themselves or the handlers are executed.
func (c *Caller) exec(command string, client *Client, event *Event) { func (c *Caller) exec(command string, client *Client, event *Event) {
// Build a stack of callbacks which can be executed concurrently. // Build a stack of handlers which can be executed concurrently.
var stack []execStack var stack []execStack
// var execstack []Callback
c.mu.RLock() c.mu.RLock()
// Get internal callbacks first. // Get internal handlers first.
if _, ok := c.internal[command]; ok { if _, ok := c.internal[command]; ok {
for cuid := range c.internal[command] { for cuid := range c.internal[command] {
stack = append(stack, execStack{c.internal[command][cuid], cuid}) stack = append(stack, execStack{c.internal[command][cuid], cuid})
} }
} }
// Aaand then external callbacks. // Aaand then external handlers.
if _, ok := c.external[command]; ok { if _, ok := c.external[command]; ok {
for cuid := range c.external[command] { for cuid := range c.external[command] {
stack = append(stack, execStack{c.external[command][cuid], cuid}) stack = append(stack, execStack{c.external[command][cuid], cuid})
@ -175,49 +174,49 @@ func (c *Caller) exec(command string, client *Client, event *Event) {
} }
c.mu.RUnlock() c.mu.RUnlock()
// Run all callbacks concurrently across the same event. This should // Run all handlers concurrently across the same event. This should
// still help prevent mis-ordered events, while speeding up the // still help prevent mis-ordered events, while speeding up the
// execution speed. // execution speed.
c.wg.Add(len(stack)) c.wg.Add(len(stack))
for i := 0; i < len(stack); i++ { for i := 0; i < len(stack); i++ {
go func(index int) { go func(index int) {
c.debug.Printf("executing callback %s for event %s", stack[index].cuid, command) c.debug.Printf("executing handler %s for event %s", stack[index].cuid, command)
start := time.Now() start := time.Now()
stack[index].Callback.Execute(client, *event) stack[index].Execute(client, *event)
c.debug.Printf("execution of %s took %s", stack[index].cuid, time.Since(start)) c.debug.Printf("execution of %s took %s", stack[index].cuid, time.Since(start))
c.wg.Done() c.wg.Done()
}(i) }(i)
} }
// Wait for all of the callbacks to complete. Not doing this may cause // Wait for all of the handlers to complete. Not doing this may cause
// new events from becoming ahead of older callbacks. // new events from becoming ahead of older handlers.
c.wg.Wait() c.wg.Wait()
} }
// ClearAll clears all external callbacks currently setup within the client. // ClearAll clears all external handlers currently setup within the client.
// This ignores internal callbacks. // This ignores internal handlers.
func (c *Caller) ClearAll() { func (c *Caller) ClearAll() {
c.mu.Lock() c.mu.Lock()
c.external = map[string]map[string]Callback{} c.external = map[string]map[string]Handler{}
c.mu.Unlock() c.mu.Unlock()
c.debug.Print("cleared all external callbacks") c.debug.Print("cleared all external handlers")
} }
// clearInternal clears all internal callbacks currently setup within the // clearInternal clears all internal handlers currently setup within the
// client. // client.
func (c *Caller) clearInternal() { func (c *Caller) clearInternal() {
c.mu.Lock() c.mu.Lock()
c.internal = map[string]map[string]Callback{} c.internal = map[string]map[string]Handler{}
c.mu.Unlock() c.mu.Unlock()
c.debug.Print("cleared all internal callbacks") c.debug.Print("cleared all internal handlers")
} }
// Clear clears all of the callbacks for the given event. // Clear clears all of the handlers for the given event.
// This ignores internal callbacks. // This ignores internal handlers.
func (c *Caller) Clear(cmd string) { func (c *Caller) Clear(cmd string) {
cmd = strings.ToUpper(cmd) cmd = strings.ToUpper(cmd)
@ -227,12 +226,12 @@ func (c *Caller) Clear(cmd string) {
} }
c.mu.Unlock() c.mu.Unlock()
c.debug.Printf("cleared external callbacks for %q", cmd) c.debug.Printf("cleared external handlers for %q", cmd)
} }
// Remove removes the callback with cuid from the callback stack. success // Remove removes the handler with cuid from the handler stack. success
// indicates that it existed, and has been removed. If not success, it // indicates that it existed, and has been removed. If not success, it
// wasn't a registered callback. // wasn't a registered handler.
func (c *Caller) Remove(cuid string) (success bool) { func (c *Caller) Remove(cuid string) (success bool) {
c.mu.Lock() c.mu.Lock()
success = c.remove(cuid) success = c.remove(cuid)
@ -249,19 +248,19 @@ func (c *Caller) remove(cuid string) (success bool) {
return false return false
} }
// Check if the irc command/event has any callbacks on it. // Check if the irc command/event has any handlers on it.
if _, ok := c.external[cmd]; !ok { if _, ok := c.external[cmd]; !ok {
return false return false
} }
// Check to see if it's actually a registered callback. // Check to see if it's actually a registered handler.
if _, ok := c.external[cmd][cuid]; !ok { if _, ok := c.external[cmd][cuid]; !ok {
return false return false
} }
delete(c.external[cmd], uid) delete(c.external[cmd], uid)
c.debug.Printf("removed callback %q", cuid) c.debug.Printf("removed handler %q", cuid)
// Assume success. // Assume success.
return true return true
@ -269,60 +268,60 @@ func (c *Caller) remove(cuid string) (success bool) {
// sregister is much like Caller.register(), except that it safely locks // sregister is much like Caller.register(), except that it safely locks
// the Caller mutex. // the Caller mutex.
func (c *Caller) sregister(internal bool, cmd string, callback Callback) (cuid string) { func (c *Caller) sregister(internal bool, cmd string, handler Handler) (cuid string) {
c.mu.Lock() c.mu.Lock()
cuid = c.register(internal, cmd, callback) cuid = c.register(internal, cmd, handler)
c.mu.Unlock() c.mu.Unlock()
return cuid return cuid
} }
// register will register a callback in the internal tracker. Unsafe (you // register will register a handler in the internal tracker. Unsafe (you
// must lock c.mu yourself!) // must lock c.mu yourself!)
func (c *Caller) register(internal bool, cmd string, callback Callback) (cuid string) { func (c *Caller) register(internal bool, cmd string, handler Handler) (cuid string) {
var uid string var uid string
cmd = strings.ToUpper(cmd) cmd = strings.ToUpper(cmd)
if internal { if internal {
if _, ok := c.internal[cmd]; !ok { if _, ok := c.internal[cmd]; !ok {
c.internal[cmd] = map[string]Callback{} c.internal[cmd] = map[string]Handler{}
} }
cuid, uid = c.cuid(cmd, 20) cuid, uid = c.cuid(cmd, 20)
c.internal[cmd][uid] = callback c.internal[cmd][uid] = handler
} else { } else {
if _, ok := c.external[cmd]; !ok { if _, ok := c.external[cmd]; !ok {
c.external[cmd] = map[string]Callback{} c.external[cmd] = map[string]Handler{}
} }
cuid, uid = c.cuid(cmd, 20) cuid, uid = c.cuid(cmd, 20)
c.external[cmd][uid] = callback c.external[cmd][uid] = handler
} }
c.debug.Printf("registering callback for %q with cuid %q (internal: %t)", cmd, cuid, internal) c.debug.Printf("registering handler for %q with cuid %q (internal: %t)", cmd, cuid, internal)
return cuid return cuid
} }
// AddHandler registers a callback (matching the Callback interface) for the // AddHandler registers a handler (matching the handler interface) for the
// given event. cuid is the callback uid which can be used to remove the // given event. cuid is the handler uid which can be used to remove the
// callback with Caller.Remove(). // handler with Caller.Remove().
func (c *Caller) AddHandler(cmd string, callback Callback) (cuid string) { func (c *Caller) AddHandler(cmd string, handler Handler) (cuid string) {
return c.sregister(false, cmd, callback) return c.sregister(false, cmd, handler)
} }
// Add registers the callback function for the given event. cuid is the // Add registers the handler function for the given event. cuid is the
// callback uid which can be used to remove the callback with Caller.Remove(). // handler uid which can be used to remove the handler with Caller.Remove().
func (c *Caller) Add(cmd string, callback func(c *Client, e Event)) (cuid string) { func (c *Caller) Add(cmd string, handler func(c *Client, e Event)) (cuid string) {
return c.sregister(false, cmd, CallbackFunc(callback)) return c.sregister(false, cmd, HandlerFunc(handler))
} }
// AddBg registers the callback function for the given event and executes it // AddBg registers the handler function for the given event and executes it
// in a go-routine. cuid is the callback uid which can be used to remove the // in a go-routine. cuid is the handler uid which can be used to remove the
// callback with Caller.Remove(). // handler with Caller.Remove().
func (c *Caller) AddBg(cmd string, callback func(c *Client, e Event)) (cuid string) { func (c *Caller) AddBg(cmd string, handler func(c *Client, e Event)) (cuid string) {
return c.sregister(false, cmd, CallbackFunc(func(c *Client, e Event) { return c.sregister(false, cmd, HandlerFunc(func(c *Client, e Event) {
go callback(c, e) go handler(c, e)
})) }))
} }

@ -31,8 +31,8 @@ type Client struct {
// initTime represents the creation time of the client. // initTime represents the creation time of the client.
initTime time.Time initTime time.Time
// Callbacks is a handler which manages internal and external callbacks. // Handlers is a handler which manages internal and external handlers.
Callbacks *Caller Handlers *Caller
// CTCP is a handler which manages internal and external CTCP handlers. // CTCP is a handler which manages internal and external CTCP handlers.
CTCP *CTCP CTCP *CTCP
@ -155,13 +155,13 @@ func New(config Config) *Client {
c.debug.Print("initializing debugging") c.debug.Print("initializing debugging")
// Setup the caller. // Setup the caller.
c.Callbacks = newCaller(c.debug) c.Handlers = newCaller(c.debug)
// Give ourselves a new state. // Give ourselves a new state.
c.state = newState() c.state = newState()
// Register builtin handlers. // Register builtin handlers.
c.registerHandlers() c.registerBuiltin()
// Register default CTCP responses. // Register default CTCP responses.
c.CTCP.addDefaultHandlers() c.CTCP.addDefaultHandlers()
@ -170,25 +170,25 @@ func New(config Config) *Client {
} }
// DisableTracking disables all channel and user-level tracking, and clears // DisableTracking disables all channel and user-level tracking, and clears
// all internal callbacks. Useful for highly embedded scripts with single // all internal handlers. Useful for highly embedded scripts with single
// purposes. This cannot be un-done. // purposes. This cannot be un-done.
func (c *Client) DisableTracking() { func (c *Client) DisableTracking() {
c.debug.Print("disabling tracking") c.debug.Print("disabling tracking")
c.Config.disableTracking = true c.Config.disableTracking = true
c.Callbacks.clearInternal() c.Handlers.clearInternal()
c.state.mu.Lock() c.state.mu.Lock()
c.state.channels = nil c.state.channels = nil
c.state.mu.Unlock() c.state.mu.Unlock()
c.registerHandlers() c.registerBuiltin()
} }
// DisableCapTracking disables all network/server capability tracking, and // DisableCapTracking disables all network/server capability tracking, and
// clears all internal callbacks. This includes determining what feature the // clears all internal handlers. This includes determining what feature the
// IRC server supports, what the "NETWORK=" variables are, and other useful // IRC server supports, what the "NETWORK=" variables are, and other useful
// stuff. DisableTracking() cannot be called if you want to also track // stuff. DisableTracking() cannot be called if you want to also track
// capabilities. // capabilities.
func (c *Client) DisableCapTracking() { func (c *Client) DisableCapTracking() {
// No need to mess with internal callbacks. That should already be // No need to mess with internal handlers. That should already be
// handled by the clear in Client.DisableTracking(). // handled by the clear in Client.DisableTracking().
if c.Config.disableCapTracking { if c.Config.disableCapTracking {
return return
@ -196,8 +196,8 @@ func (c *Client) DisableCapTracking() {
c.debug.Print("disabling CAP tracking") c.debug.Print("disabling CAP tracking")
c.Config.disableCapTracking = true c.Config.disableCapTracking = true
c.Callbacks.clearInternal() c.Handlers.clearInternal()
c.registerHandlers() c.registerBuiltin()
} }
// DisableNickCollision disables the clients auto-response to nickname // DisableNickCollision disables the clients auto-response to nickname
@ -207,11 +207,11 @@ func (c *Client) DisableCapTracking() {
func (c *Client) DisableNickCollision() { func (c *Client) DisableNickCollision() {
c.debug.Print("disabling nick collision prevention") c.debug.Print("disabling nick collision prevention")
c.Config.disableNickCollision = true c.Config.disableNickCollision = true
c.Callbacks.clearInternal() c.Handlers.clearInternal()
c.state.mu.Lock() c.state.mu.Lock()
c.state.channels = nil c.state.channels = nil
c.state.mu.Unlock() c.state.mu.Unlock()
c.registerHandlers() c.registerBuiltin()
} }
// cleanup is used to close out all threads used by the client, like read and // cleanup is used to close out all threads used by the client, like read and
@ -264,10 +264,10 @@ func (c *Client) QuitWithMessage(message string) {
} }
// Stop exits the clients main loop and any other goroutines created by // Stop exits the clients main loop and any other goroutines created by
// the client itself. This does not include callbacks, as they will run for // the client itself. This does not include handlers, as they will run for
// any incoming events prior to when Stop() or Quit() was called, until the // any incoming events prior to when Stop() or Quit() was called, until the
// event queue is empty and execution has completed for those callbacks. This // event queue is empty and execution has completed for those handlers. This
// means that you are responsible to ensure that your callbacks due not // means that you are responsible to ensure that your handlers due not
// execute forever. Use Client.Quit() first if you want to disconnect the // execute forever. Use Client.Quit() first if you want to disconnect the
// client from the server/connection gracefully. // client from the server/connection gracefully.
func (c *Client) Stop() { func (c *Client) Stop() {
@ -467,7 +467,7 @@ func (c *Client) execLoop(ctx context.Context) {
for { for {
select { select {
case event := <-c.Events: case event := <-c.Events:
c.RunCallbacks(event) c.RunHandlers(event)
case <-ctx.Done(): case <-ctx.Done():
return return
} }
@ -494,8 +494,8 @@ func (c *Client) Lifetime() time.Duration {
return time.Since(c.initTime) return time.Since(c.initTime)
} }
// Send sends an event to the server. Use Client.RunCallback() if you are // Send sends an event to the server. Use Client.RunHandlers() if you are
// simply looking to trigger callbacks with an event. // simply looking to trigger handlers with an event.
func (c *Client) Send(event *Event) error { func (c *Client) Send(event *Event) error {
if !c.Config.AllowFlood { if !c.Config.AllowFlood {
<-time.After(c.state.rate(event.Len())) <-time.After(c.state.rate(event.Len()))

@ -47,18 +47,18 @@ func Example_simple() {
Name: "Example bot", Name: "Example bot",
}) })
client.Callbacks.Add(girc.CONNECTED, func(c *girc.Client, e girc.Event) { client.Handlers.Add(girc.CONNECTED, func(c *girc.Client, e girc.Event) {
c.Join("#dev") c.Join("#dev")
}) })
client.Callbacks.Add(girc.PRIVMSG, func(c *girc.Client, e girc.Event) { client.Handlers.Add(girc.PRIVMSG, func(c *girc.Client, e girc.Event) {
if strings.Contains(e.Trailing, "hello") { if strings.Contains(e.Trailing, "hello") {
c.Message(e.Params[0], "hello world!") c.Message(e.Params[0], "hello world!")
} }
}) })
// Log useful IRC events. // Log useful IRC events.
client.Callbacks.Add(girc.ALLEVENTS, func(c *girc.Client, e girc.Event) { client.Handlers.Add(girc.ALLEVENTS, func(c *girc.Client, e girc.Event) {
// girc.Event.Pretty() returns true for events which are useful and // girc.Event.Pretty() returns true for events which are useful and
// that can be prettified. Use Event.String() to get the raw string // that can be prettified. Use Event.String() to get the raw string
// for all events. // for all events.
@ -87,11 +87,11 @@ func Example_commands() {
Name: "Example bot", Name: "Example bot",
}) })
client.Callbacks.Add(girc.CONNECTED, func(c *girc.Client, e girc.Event) { client.Handlers.Add(girc.CONNECTED, func(c *girc.Client, e girc.Event) {
c.Join("#channel", "#other-channel") c.Join("#channel", "#other-channel")
}) })
client.Callbacks.Add(girc.PRIVMSG, func(c *girc.Client, e girc.Event) { client.Handlers.Add(girc.PRIVMSG, func(c *girc.Client, e girc.Event) {
if strings.HasPrefix(e.Trailing, "!hello") { if strings.HasPrefix(e.Trailing, "!hello") {
c.Message(e.Params[0], "hello world!") c.Message(e.Params[0], "hello world!")
return return
@ -110,7 +110,7 @@ func Example_commands() {
}) })
// Log ALL events. // Log ALL events.
client.Callbacks.Add(girc.ALLEVENTS, func(c *girc.Client, e girc.Event) { client.Handlers.Add(girc.ALLEVENTS, func(c *girc.Client, e girc.Event) {
// The use of girc.StripRaw() is to get rid of any potential // The use of girc.StripRaw() is to get rid of any potential
// non-printable characters. // non-printable characters.
fmt.Println(girc.StripRaw(e.String())) fmt.Println(girc.StripRaw(e.String()))

@ -111,7 +111,7 @@ func encodeCTCPRaw(cmd, text string) (out string) {
// CTCP handles the storage and execution of CTCP handlers against incoming // CTCP handles the storage and execution of CTCP handlers against incoming
// CTCP events. // CTCP events.
type CTCP struct { type CTCP struct {
// mu is the mutex that should be used when accessing callbacks. // mu is the mutex that should be used when accessing any ctcp handlers.
mu sync.RWMutex mu sync.RWMutex
// handlers is a map of CTCP message -> functions. // handlers is a map of CTCP message -> functions.
handlers map[string]CTCPHandler handlers map[string]CTCPHandler