Callbacks -> Handlers
This commit is contained in:
parent
c9243b15b3
commit
69a6d77ac8
@ -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
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)
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
38
client.go
38
client.go
@ -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()))
|
||||||
|
2
ctcp.go
2
ctcp.go
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user