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

View File

@ -9,67 +9,67 @@ import (
"time"
)
// registerHandlers sets up built-in callbacks/helpers, based on client
// registerBuiltin sets up built-in handlers, based on client
// configuration.
func (c *Client) registerHandlers() {
func (c *Client) registerBuiltin() {
c.debug.Print("registering built-in handlers")
c.Callbacks.mu.Lock()
c.Handlers.mu.Lock()
// 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)
}))
c.Callbacks.register(true, PING, CallbackFunc(handlePING))
c.Handlers.register(true, PING, HandlerFunc(handlePING))
if !c.Config.disableTracking {
// Joins/parts/anything that may add/remove/rename users.
c.Callbacks.register(true, JOIN, CallbackFunc(handleJOIN))
c.Callbacks.register(true, PART, CallbackFunc(handlePART))
c.Callbacks.register(true, KICK, CallbackFunc(handleKICK))
c.Callbacks.register(true, QUIT, CallbackFunc(handleQUIT))
c.Callbacks.register(true, NICK, CallbackFunc(handleNICK))
c.Callbacks.register(true, RPL_NAMREPLY, CallbackFunc(handleNAMES))
c.Handlers.register(true, JOIN, HandlerFunc(handleJOIN))
c.Handlers.register(true, PART, HandlerFunc(handlePART))
c.Handlers.register(true, KICK, HandlerFunc(handleKICK))
c.Handlers.register(true, QUIT, HandlerFunc(handleQUIT))
c.Handlers.register(true, NICK, HandlerFunc(handleNICK))
c.Handlers.register(true, RPL_NAMREPLY, HandlerFunc(handleNAMES))
// Modes.
c.Callbacks.register(true, MODE, CallbackFunc(handleMODE))
c.Callbacks.register(true, RPL_CHANNELMODEIS, CallbackFunc(handleMODE))
c.Handlers.register(true, MODE, HandlerFunc(handleMODE))
c.Handlers.register(true, RPL_CHANNELMODEIS, HandlerFunc(handleMODE))
// WHO/WHOX responses.
c.Callbacks.register(true, RPL_WHOREPLY, CallbackFunc(handleWHO))
c.Callbacks.register(true, RPL_WHOSPCRPL, CallbackFunc(handleWHO))
c.Handlers.register(true, RPL_WHOREPLY, HandlerFunc(handleWHO))
c.Handlers.register(true, RPL_WHOSPCRPL, HandlerFunc(handleWHO))
// Other misc. useful stuff.
c.Callbacks.register(true, TOPIC, CallbackFunc(handleTOPIC))
c.Callbacks.register(true, RPL_TOPIC, CallbackFunc(handleTOPIC))
c.Callbacks.register(true, RPL_MYINFO, CallbackFunc(handleMYINFO))
c.Callbacks.register(true, RPL_ISUPPORT, CallbackFunc(handleISUPPORT))
c.Callbacks.register(true, RPL_MOTDSTART, CallbackFunc(handleMOTD))
c.Callbacks.register(true, RPL_MOTD, CallbackFunc(handleMOTD))
c.Handlers.register(true, TOPIC, HandlerFunc(handleTOPIC))
c.Handlers.register(true, RPL_TOPIC, HandlerFunc(handleTOPIC))
c.Handlers.register(true, RPL_MYINFO, HandlerFunc(handleMYINFO))
c.Handlers.register(true, RPL_ISUPPORT, HandlerFunc(handleISUPPORT))
c.Handlers.register(true, RPL_MOTDSTART, HandlerFunc(handleMOTD))
c.Handlers.register(true, RPL_MOTD, HandlerFunc(handleMOTD))
// Keep users lastactive times up to date.
c.Callbacks.register(true, PRIVMSG, CallbackFunc(updateLastActive))
c.Callbacks.register(true, NOTICE, CallbackFunc(updateLastActive))
c.Callbacks.register(true, TOPIC, CallbackFunc(updateLastActive))
c.Callbacks.register(true, KICK, CallbackFunc(updateLastActive))
c.Handlers.register(true, PRIVMSG, HandlerFunc(updateLastActive))
c.Handlers.register(true, NOTICE, HandlerFunc(updateLastActive))
c.Handlers.register(true, TOPIC, HandlerFunc(updateLastActive))
c.Handlers.register(true, KICK, HandlerFunc(updateLastActive))
// CAP IRCv3-specific tracking and functionality.
if !c.Config.disableCapTracking {
c.Callbacks.register(true, CAP, CallbackFunc(handleCAP))
c.Callbacks.register(true, CAP_CHGHOST, CallbackFunc(handleCHGHOST))
c.Callbacks.register(true, CAP_AWAY, CallbackFunc(handleAWAY))
c.Callbacks.register(true, CAP_ACCOUNT, CallbackFunc(handleACCOUNT))
c.Callbacks.register(true, ALLEVENTS, CallbackFunc(handleTags))
c.Handlers.register(true, CAP, HandlerFunc(handleCAP))
c.Handlers.register(true, CAP_CHGHOST, HandlerFunc(handleCHGHOST))
c.Handlers.register(true, CAP_AWAY, HandlerFunc(handleAWAY))
c.Handlers.register(true, CAP_ACCOUNT, HandlerFunc(handleACCOUNT))
c.Handlers.register(true, ALLEVENTS, HandlerFunc(handleTags))
}
}
// Nickname collisions.
if !c.Config.disableNickCollision {
c.Callbacks.register(true, ERR_NICKNAMEINUSE, CallbackFunc(nickCollisionHandler))
c.Callbacks.register(true, ERR_NICKCOLLISION, CallbackFunc(nickCollisionHandler))
c.Callbacks.register(true, ERR_UNAVAILRESOURCE, CallbackFunc(nickCollisionHandler))
c.Handlers.register(true, ERR_NICKNAMEINUSE, HandlerFunc(nickCollisionHandler))
c.Handlers.register(true, ERR_NICKCOLLISION, HandlerFunc(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
@ -286,7 +286,7 @@ func handleMYINFO(c *Client, e Event) {
// For example, things like max channel name length, or nickname length.
func handleISUPPORT(c *Client, e Event) {
// 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.
// Also known as RPL_PROTOCTL.

167
caller.go
View File

@ -13,8 +13,8 @@ import (
"time"
)
// RunCallbacks manually runs callbacks for a given event.
func (c *Client) RunCallbacks(event *Event) {
// RunHandlers manually runs handlers for a given event.
func (c *Client) RunHandlers(event *Event) {
if event == nil {
return
}
@ -22,11 +22,11 @@ func (c *Client) RunCallbacks(event *Event) {
// Log the event.
c.debug.Print("< " + StripRaw(event.String()))
// Regular wildcard callbacks.
c.Callbacks.exec(ALLEVENTS, c, event.Copy())
// Regular wildcard handlers.
c.Handlers.exec(ALLEVENTS, c, event.Copy())
// Then regular callbacks.
c.Callbacks.exec(event.Command, c, event.Copy())
// Then regular handlers.
c.Handlers.exec(event.Command, c, event.Copy())
// Check if it's a CTCP.
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()
type Callback interface {
type Handler interface {
Execute(*Client, Event)
}
// CallbackFunc is a type that represents the function necessary to
// implement Callback.
type CallbackFunc func(c *Client, e Event)
// HandlerFunc is a type that represents the function necessary to
// implement Handler.
type HandlerFunc func(c *Client, e Event)
// Execute calls the CallbackFunc with the sender and irc message.
func (f CallbackFunc) Execute(c *Client, e Event) {
// Execute calls the HandlerFunc with the sender and irc message.
func (f HandlerFunc) Execute(c *Client, e Event) {
f(c, e)
}
// Caller manages internal and external (user facing) callbacks.
//
// external/internal keys are of structure:
// map[COMMAND][CUID]Callback
//
// Also of note: "COMMAND" should always be uppercase for normalization.
// Caller manages internal and external (user facing) handlers.
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
// 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
// external is a map of user facing callbacks.
external map[string]map[string]Callback
// internal is a map of internally used callbacks for the client.
internal map[string]map[string]Callback
// external/internal keys are of structure:
// map[COMMAND][CUID]Handler
// 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 *log.Logger
}
// newCaller creates and initializes a new callback handler.
// newCaller creates and initializes a new handler.
func newCaller(debugger *log.Logger) *Caller {
c := &Caller{
external: map[string]map[string]Callback{},
internal: map[string]map[string]Callback{},
external: map[string]map[string]Handler{},
internal: map[string]map[string]Handler{},
debug: debugger,
}
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 {
var total int
@ -94,7 +94,7 @@ func (c *Caller) Len() int {
}
// 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 {
var total int
@ -125,7 +125,7 @@ func (c *Caller) String() string {
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) {
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
// external/internal callback maps.
// external/internal handler maps.
func (c *Caller) cuidToID(input string) (cmd, uid string) {
// Ignore the errors because the strings will default to empty anyway.
_, _ = fmt.Sscanf(input, "%s:%s", &cmd, &uid)
@ -145,29 +145,28 @@ func (c *Caller) cuidToID(input string) (cmd, uid string) {
}
type execStack struct {
Callback Callback
cuid string
Handler
cuid string
}
// exec executes all callbacks pertaining to specified event. Internal first,
// exec executes all handlers pertaining to specified event. Internal first,
// then external.
//
// 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) {
// Build a stack of callbacks which can be executed concurrently.
// Build a stack of handlers which can be executed concurrently.
var stack []execStack
// var execstack []Callback
c.mu.RLock()
// Get internal callbacks first.
// Get internal handlers first.
if _, ok := c.internal[command]; ok {
for cuid := range c.internal[command] {
stack = append(stack, execStack{c.internal[command][cuid], cuid})
}
}
// Aaand then external callbacks.
// Aaand then external handlers.
if _, ok := c.external[command]; ok {
for cuid := range c.external[command] {
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()
// 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
// execution speed.
c.wg.Add(len(stack))
for i := 0; i < len(stack); i++ {
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()
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.wg.Done()
}(i)
}
// Wait for all of the callbacks to complete. Not doing this may cause
// new events from becoming ahead of older callbacks.
// Wait for all of the handlers to complete. Not doing this may cause
// new events from becoming ahead of older handlers.
c.wg.Wait()
}
// ClearAll clears all external callbacks currently setup within the client.
// This ignores internal callbacks.
// ClearAll clears all external handlers currently setup within the client.
// This ignores internal handlers.
func (c *Caller) ClearAll() {
c.mu.Lock()
c.external = map[string]map[string]Callback{}
c.external = map[string]map[string]Handler{}
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.
func (c *Caller) clearInternal() {
c.mu.Lock()
c.internal = map[string]map[string]Callback{}
c.internal = map[string]map[string]Handler{}
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.
// This ignores internal callbacks.
// Clear clears all of the handlers for the given event.
// This ignores internal handlers.
func (c *Caller) Clear(cmd string) {
cmd = strings.ToUpper(cmd)
@ -227,12 +226,12 @@ func (c *Caller) Clear(cmd string) {
}
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
// wasn't a registered callback.
// wasn't a registered handler.
func (c *Caller) Remove(cuid string) (success bool) {
c.mu.Lock()
success = c.remove(cuid)
@ -249,19 +248,19 @@ func (c *Caller) remove(cuid string) (success bool) {
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 {
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 {
return false
}
delete(c.external[cmd], uid)
c.debug.Printf("removed callback %q", cuid)
c.debug.Printf("removed handler %q", cuid)
// Assume success.
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
// 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()
cuid = c.register(internal, cmd, callback)
cuid = c.register(internal, cmd, handler)
c.mu.Unlock()
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!)
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
cmd = strings.ToUpper(cmd)
if internal {
if _, ok := c.internal[cmd]; !ok {
c.internal[cmd] = map[string]Callback{}
c.internal[cmd] = map[string]Handler{}
}
cuid, uid = c.cuid(cmd, 20)
c.internal[cmd][uid] = callback
c.internal[cmd][uid] = handler
} else {
if _, ok := c.external[cmd]; !ok {
c.external[cmd] = map[string]Callback{}
c.external[cmd] = map[string]Handler{}
}
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
}
// AddHandler registers a callback (matching the Callback interface) for the
// given event. cuid is the callback uid which can be used to remove the
// callback with Caller.Remove().
func (c *Caller) AddHandler(cmd string, callback Callback) (cuid string) {
return c.sregister(false, cmd, callback)
// AddHandler registers a handler (matching the handler interface) for the
// given event. cuid is the handler uid which can be used to remove the
// handler with Caller.Remove().
func (c *Caller) AddHandler(cmd string, handler Handler) (cuid string) {
return c.sregister(false, cmd, handler)
}
// Add registers the callback function for the given event. cuid is the
// callback uid which can be used to remove the callback with Caller.Remove().
func (c *Caller) Add(cmd string, callback func(c *Client, e Event)) (cuid string) {
return c.sregister(false, cmd, CallbackFunc(callback))
// Add registers the handler function for the given event. cuid is the
// handler uid which can be used to remove the handler with Caller.Remove().
func (c *Caller) Add(cmd string, handler func(c *Client, e Event)) (cuid string) {
return c.sregister(false, cmd, HandlerFunc(handler))
}
// AddBg registers the callback function for the given event and executes it
// in a go-routine. cuid is the callback uid which can be used to remove the
// callback with Caller.Remove().
func (c *Caller) AddBg(cmd string, callback func(c *Client, e Event)) (cuid string) {
return c.sregister(false, cmd, CallbackFunc(func(c *Client, e Event) {
go callback(c, e)
// AddBg registers the handler function for the given event and executes it
// in a go-routine. cuid is the handler uid which can be used to remove the
// handler with Caller.Remove().
func (c *Caller) AddBg(cmd string, handler func(c *Client, e Event)) (cuid string) {
return c.sregister(false, cmd, HandlerFunc(func(c *Client, e Event) {
go handler(c, e)
}))
}

View File

@ -31,8 +31,8 @@ type Client struct {
// initTime represents the creation time of the client.
initTime time.Time
// Callbacks is a handler which manages internal and external callbacks.
Callbacks *Caller
// Handlers is a handler which manages internal and external handlers.
Handlers *Caller
// CTCP is a handler which manages internal and external CTCP handlers.
CTCP *CTCP
@ -155,13 +155,13 @@ func New(config Config) *Client {
c.debug.Print("initializing debugging")
// Setup the caller.
c.Callbacks = newCaller(c.debug)
c.Handlers = newCaller(c.debug)
// Give ourselves a new state.
c.state = newState()
// Register builtin handlers.
c.registerHandlers()
c.registerBuiltin()
// Register default CTCP responses.
c.CTCP.addDefaultHandlers()
@ -170,25 +170,25 @@ func New(config Config) *Client {
}
// 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.
func (c *Client) DisableTracking() {
c.debug.Print("disabling tracking")
c.Config.disableTracking = true
c.Callbacks.clearInternal()
c.Handlers.clearInternal()
c.state.mu.Lock()
c.state.channels = nil
c.state.mu.Unlock()
c.registerHandlers()
c.registerBuiltin()
}
// 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
// stuff. DisableTracking() cannot be called if you want to also track
// capabilities.
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().
if c.Config.disableCapTracking {
return
@ -196,8 +196,8 @@ func (c *Client) DisableCapTracking() {
c.debug.Print("disabling CAP tracking")
c.Config.disableCapTracking = true
c.Callbacks.clearInternal()
c.registerHandlers()
c.Handlers.clearInternal()
c.registerBuiltin()
}
// DisableNickCollision disables the clients auto-response to nickname
@ -207,11 +207,11 @@ func (c *Client) DisableCapTracking() {
func (c *Client) DisableNickCollision() {
c.debug.Print("disabling nick collision prevention")
c.Config.disableNickCollision = true
c.Callbacks.clearInternal()
c.Handlers.clearInternal()
c.state.mu.Lock()
c.state.channels = nil
c.state.mu.Unlock()
c.registerHandlers()
c.registerBuiltin()
}
// 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
// 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
// event queue is empty and execution has completed for those callbacks. This
// means that you are responsible to ensure that your callbacks due not
// event queue is empty and execution has completed for those handlers. This
// means that you are responsible to ensure that your handlers due not
// execute forever. Use Client.Quit() first if you want to disconnect the
// client from the server/connection gracefully.
func (c *Client) Stop() {
@ -467,7 +467,7 @@ func (c *Client) execLoop(ctx context.Context) {
for {
select {
case event := <-c.Events:
c.RunCallbacks(event)
c.RunHandlers(event)
case <-ctx.Done():
return
}
@ -494,8 +494,8 @@ func (c *Client) Lifetime() time.Duration {
return time.Since(c.initTime)
}
// Send sends an event to the server. Use Client.RunCallback() if you are
// simply looking to trigger callbacks with an event.
// Send sends an event to the server. Use Client.RunHandlers() if you are
// simply looking to trigger handlers with an event.
func (c *Client) Send(event *Event) error {
if !c.Config.AllowFlood {
<-time.After(c.state.rate(event.Len()))

View File

@ -47,18 +47,18 @@ func Example_simple() {
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")
})
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") {
c.Message(e.Params[0], "hello world!")
}
})
// 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
// that can be prettified. Use Event.String() to get the raw string
// for all events.
@ -87,11 +87,11 @@ func Example_commands() {
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")
})
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") {
c.Message(e.Params[0], "hello world!")
return
@ -110,7 +110,7 @@ func Example_commands() {
})
// 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
// non-printable characters.
fmt.Println(girc.StripRaw(e.String()))

View File

@ -111,7 +111,7 @@ func encodeCTCPRaw(cmd, text string) (out string) {
// CTCP handles the storage and execution of CTCP handlers against incoming
// CTCP events.
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
// handlers is a map of CTCP message -> functions.
handlers map[string]CTCPHandler