girc-atomic/callback.go

168 lines
4.2 KiB
Go

// Copyright 2016 Liam Stanley <me@liamstanley.io>. All rights reserved.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
package girc
import (
"fmt"
"strconv"
"strings"
)
func (c *Client) execCallbacks(command string, event *Event) {
if callbacks, ok := c.callbacks["routine:"+command]; ok {
for i := 0; i < len(callbacks); i++ {
if callbacks[i] == nil {
continue
}
go callbacks[i].Execute(c, *event)
}
}
if callbacks, ok := c.callbacks[command]; ok {
for i := 0; i < len(callbacks); i++ {
if callbacks[i] == nil {
continue
}
callbacks[i].Execute(c, *event)
}
}
}
// RunCallbacks manually runs callbacks for a given event.
func (c *Client) RunCallbacks(event *Event) {
// Log the event.
c.log.Print("<-- " + event.Raw())
// Regular wildcard callbacks.
c.execCallbacks(ALLEVENTS, event)
// Then regular non-threaded callbacks.
c.execCallbacks(event.Command, event)
}
// ClearAllCallbacks clears all callbacks currently setup within the client.
//
// This ignores internal callbacks for the client.
func (c *Client) ClearAllCallbacks() {
// registerHelpers should clean all callbacks and setup internal ones as
// necessary.
c.registerHelpers()
}
// ClearCallbacks clears all of the callbacks for the given event.
//
// This ignores internal callbacks for the client.
func (c *Client) ClearCallbacks(cmd string) {
for i := 0; i < len(c.callbacks[cmd]); i++ {
c.RemoveCallback(fmt.Sprintf("%s:%d", cmd, i))
}
for i := 0; i < len(c.callbacks["routine:"+cmd]); i++ {
c.RemoveCallback(fmt.Sprintf("routine:%s:%d", cmd, i))
}
}
// RemoveCallback removes the callback with id from the callback stack.
func (c *Client) RemoveCallback(id string) {
// Check to see if it's an internal callback.
for i := 0; i < len(c.internalCallbacks); i++ {
if id == c.internalCallbacks[i] {
return
}
}
var cmd string
var index int
parts := strings.Split(id, ":")
if len(parts) < 2 {
// Needs to be at least CMD:INDEX.
return
}
cmd = strings.Join(parts[0:len(parts)-1], ":")
index, err := strconv.Atoi(parts[len(parts)-1])
if err != nil {
return
}
if len(c.callbacks[cmd]) > (index + 1) {
// Index doesn't look to exist.
return
}
// Ignore if it's already been disabled.
if c.callbacks[cmd][index] == nil {
return
}
c.cbMux.Lock()
c.callbacks[cmd][index] = nil
c.cbMux.Unlock()
}
// trackIntCallback keeps track of all internally used callbacks.
func (c *Client) trackIntCallback(id string) {
c.cbMux.Lock()
c.internalCallbacks = append(c.internalCallbacks, id)
c.cbMux.Unlock()
}
// untrackIntCallback keeps track of all internally used callbacks.
func (c *Client) untrackIntCallback(id string) {
c.cbMux.Lock()
for i := 0; i < len(c.internalCallbacks); i++ {
if c.internalCallbacks[i] == id {
c.internalCallbacks = append(c.internalCallbacks[:i], c.internalCallbacks[i+1:]...)
}
}
c.cbMux.Unlock()
}
// AddCallbackHandler registers a callback (matching the Callback
// interface) for the given command.
func (c *Client) AddCallbackHandler(cmd string, callback Callback) (id string) {
c.cbMux.Lock()
c.callbacks[cmd] = append(c.callbacks[cmd], callback)
id = fmt.Sprintf("%s:%d", cmd, len(c.callbacks[cmd])-1)
c.cbMux.Unlock()
return id
}
// AddCallback registers the callback function for the given command.
func (c *Client) AddCallback(cmd string, callback func(c *Client, e Event)) (id string) {
c.cbMux.Lock()
c.callbacks[cmd] = append(c.callbacks[cmd], CallbackFunc(callback))
id = fmt.Sprintf("%s:%d", cmd, len(c.callbacks[cmd])-1)
c.cbMux.Unlock()
return id
}
// AddBgCallback registers the callback function for the given command
// and executes it in a go-routine.
//
// Runs after all other callbacks have been ran.
func (c *Client) AddBgCallback(cmd string, callback func(c *Client, e Event)) (id string) {
return c.AddCallback("routine:"+cmd, callback)
}
// Callback is lower level implementation of Client.AddCallback().
type Callback interface {
Execute(*Client, Event)
}
// CallbackFunc is a type that represents the function necessary to
// implement Callback.
type CallbackFunc func(c *Client, e Event)
// Execute calls the CallbackFunc with the sender and irc message.
func (f CallbackFunc) Execute(c *Client, e Event) {
f(c, e)
}