summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md2
-rw-r--r--vendor/github.com/lrstanley/girc/builtin.go80
-rw-r--r--vendor/github.com/lrstanley/girc/cap.go14
-rw-r--r--vendor/github.com/lrstanley/girc/client.go44
-rw-r--r--vendor/github.com/lrstanley/girc/commands.go21
-rw-r--r--vendor/github.com/lrstanley/girc/ctcp.go6
-rw-r--r--vendor/github.com/lrstanley/girc/event.go12
-rw-r--r--vendor/github.com/lrstanley/girc/format.go43
-rw-r--r--vendor/github.com/lrstanley/girc/handler.go131
-rw-r--r--vendor/github.com/lrstanley/girc/modes.go10
-rw-r--r--vendor/manifest2
11 files changed, 210 insertions, 155 deletions
diff --git a/README.md b/README.md
index 76fc5ad3..2cdbb904 100644
--- a/README.md
+++ b/README.md
@@ -175,7 +175,7 @@ Matterbridge wouldn't exist without these libraries:
* echo - https://github.com/labstack/echo
* gitter - https://github.com/sromku/go-gitter
* gops - https://github.com/google/gops
-* irc - https://github.com/thoj/go-ircevent
+* irc - https://github.com/lrstanley/girc
* mattermost - https://github.com/mattermost/platform
* matrix - https://github.com/matrix-org/gomatrix
* slack - https://github.com/nlopes/slack
diff --git a/vendor/github.com/lrstanley/girc/builtin.go b/vendor/github.com/lrstanley/girc/builtin.go
index aecb1e11..e7ccc199 100644
--- a/vendor/github.com/lrstanley/girc/builtin.go
+++ b/vendor/github.com/lrstanley/girc/builtin.go
@@ -16,64 +16,62 @@ func (c *Client) registerBuiltins() {
c.Handlers.mu.Lock()
// Built-in things that should always be supported.
- c.Handlers.register(true, RPL_WELCOME, HandlerFunc(func(c *Client, e Event) {
- go handleConnect(c, e)
- }))
- c.Handlers.register(true, PING, HandlerFunc(handlePING))
- c.Handlers.register(true, PONG, HandlerFunc(handlePONG))
+ c.Handlers.register(true, true, RPL_WELCOME, HandlerFunc(handleConnect))
+ c.Handlers.register(true, false, PING, HandlerFunc(handlePING))
+ c.Handlers.register(true, false, PONG, HandlerFunc(handlePONG))
if !c.Config.disableTracking {
// Joins/parts/anything that may add/remove/rename users.
- 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))
+ c.Handlers.register(true, false, JOIN, HandlerFunc(handleJOIN))
+ c.Handlers.register(true, false, PART, HandlerFunc(handlePART))
+ c.Handlers.register(true, false, KICK, HandlerFunc(handleKICK))
+ c.Handlers.register(true, false, QUIT, HandlerFunc(handleQUIT))
+ c.Handlers.register(true, false, NICK, HandlerFunc(handleNICK))
+ c.Handlers.register(true, false, RPL_NAMREPLY, HandlerFunc(handleNAMES))
// Modes.
- c.Handlers.register(true, MODE, HandlerFunc(handleMODE))
- c.Handlers.register(true, RPL_CHANNELMODEIS, HandlerFunc(handleMODE))
+ c.Handlers.register(true, false, MODE, HandlerFunc(handleMODE))
+ c.Handlers.register(true, false, RPL_CHANNELMODEIS, HandlerFunc(handleMODE))
// WHO/WHOX responses.
- c.Handlers.register(true, RPL_WHOREPLY, HandlerFunc(handleWHO))
- c.Handlers.register(true, RPL_WHOSPCRPL, HandlerFunc(handleWHO))
+ c.Handlers.register(true, false, RPL_WHOREPLY, HandlerFunc(handleWHO))
+ c.Handlers.register(true, false, RPL_WHOSPCRPL, HandlerFunc(handleWHO))
// Other misc. useful stuff.
- 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))
+ c.Handlers.register(true, false, TOPIC, HandlerFunc(handleTOPIC))
+ c.Handlers.register(true, false, RPL_TOPIC, HandlerFunc(handleTOPIC))
+ c.Handlers.register(true, false, RPL_MYINFO, HandlerFunc(handleMYINFO))
+ c.Handlers.register(true, false, RPL_ISUPPORT, HandlerFunc(handleISUPPORT))
+ c.Handlers.register(true, false, RPL_MOTDSTART, HandlerFunc(handleMOTD))
+ c.Handlers.register(true, false, RPL_MOTD, HandlerFunc(handleMOTD))
// Keep users lastactive times up to date.
- 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))
+ c.Handlers.register(true, false, PRIVMSG, HandlerFunc(updateLastActive))
+ c.Handlers.register(true, false, NOTICE, HandlerFunc(updateLastActive))
+ c.Handlers.register(true, false, TOPIC, HandlerFunc(updateLastActive))
+ c.Handlers.register(true, false, KICK, HandlerFunc(updateLastActive))
// CAP IRCv3-specific tracking and functionality.
- 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, ALL_EVENTS, HandlerFunc(handleTags))
+ c.Handlers.register(true, false, CAP, HandlerFunc(handleCAP))
+ c.Handlers.register(true, false, CAP_CHGHOST, HandlerFunc(handleCHGHOST))
+ c.Handlers.register(true, false, CAP_AWAY, HandlerFunc(handleAWAY))
+ c.Handlers.register(true, false, CAP_ACCOUNT, HandlerFunc(handleACCOUNT))
+ c.Handlers.register(true, false, ALL_EVENTS, HandlerFunc(handleTags))
// SASL IRCv3 support.
- c.Handlers.register(true, AUTHENTICATE, HandlerFunc(handleSASL))
- c.Handlers.register(true, RPL_SASLSUCCESS, HandlerFunc(handleSASL))
- c.Handlers.register(true, RPL_NICKLOCKED, HandlerFunc(handleSASLError))
- c.Handlers.register(true, ERR_SASLFAIL, HandlerFunc(handleSASLError))
- c.Handlers.register(true, ERR_SASLTOOLONG, HandlerFunc(handleSASLError))
- c.Handlers.register(true, ERR_SASLABORTED, HandlerFunc(handleSASLError))
- c.Handlers.register(true, RPL_SASLMECHS, HandlerFunc(handleSASLError))
+ c.Handlers.register(true, false, AUTHENTICATE, HandlerFunc(handleSASL))
+ c.Handlers.register(true, false, RPL_SASLSUCCESS, HandlerFunc(handleSASL))
+ c.Handlers.register(true, false, RPL_NICKLOCKED, HandlerFunc(handleSASLError))
+ c.Handlers.register(true, false, ERR_SASLFAIL, HandlerFunc(handleSASLError))
+ c.Handlers.register(true, false, ERR_SASLTOOLONG, HandlerFunc(handleSASLError))
+ c.Handlers.register(true, false, ERR_SASLABORTED, HandlerFunc(handleSASLError))
+ c.Handlers.register(true, false, RPL_SASLMECHS, HandlerFunc(handleSASLError))
}
// Nickname collisions.
- 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.Handlers.register(true, false, ERR_NICKNAMEINUSE, HandlerFunc(nickCollisionHandler))
+ c.Handlers.register(true, false, ERR_NICKCOLLISION, HandlerFunc(nickCollisionHandler))
+ c.Handlers.register(true, false, ERR_UNAVAILRESOURCE, HandlerFunc(nickCollisionHandler))
c.Handlers.mu.Unlock()
}
@@ -389,7 +387,7 @@ func handleISUPPORT(c *Client, e Event) {
c.state.Lock()
// Skip the first parameter, as it's our nickname.
for i := 1; i < len(e.Params); i++ {
- j := strings.IndexByte(e.Params[i], 0x3D) // =
+ j := strings.IndexByte(e.Params[i], '=')
if j < 1 || (j+1) == len(e.Params[i]) {
c.state.serverOptions[e.Params[i]] = ""
diff --git a/vendor/github.com/lrstanley/girc/cap.go b/vendor/github.com/lrstanley/girc/cap.go
index a63dfe9d..1d50460f 100644
--- a/vendor/github.com/lrstanley/girc/cap.go
+++ b/vendor/github.com/lrstanley/girc/cap.go
@@ -375,11 +375,11 @@ func handleTags(c *Client, e Event) {
}
const (
- prefixTag byte = 0x40 // @
- prefixTagValue byte = 0x3D // =
- prefixUserTag byte = 0x2B // +
- tagSeparator byte = 0x3B // ;
- maxTagLength int = 511 // 510 + @ and " " (space), though space usually not included.
+ prefixTag byte = '@'
+ prefixTagValue byte = '='
+ prefixUserTag byte = '+'
+ tagSeparator byte = ';'
+ maxTagLength int = 511 // 510 + @ and " " (space), though space usually not included.
)
// Tags represents the key-value pairs in IRCv3 message tags. The map contains
@@ -618,7 +618,7 @@ func validTag(name string) bool {
for i := 0; i < len(name); i++ {
// A-Z, a-z, 0-9, -/._
- if (name[i] < 0x41 || name[i] > 0x5A) && (name[i] < 0x61 || name[i] > 0x7A) && (name[i] < 0x2D || name[i] > 0x39) && name[i] != 0x5F {
+ if (name[i] < 'A' || name[i] > 'Z') && (name[i] < 'a' || name[i] > 'z') && (name[i] < '-' || name[i] > '9') && name[i] != '_' {
return false
}
}
@@ -631,7 +631,7 @@ func validTag(name string) bool {
func validTagValue(value string) bool {
for i := 0; i < len(value); i++ {
// Don't allow any invisible chars within the tag, or semicolons.
- if value[i] < 0x21 || value[i] > 0x7E || value[i] == 0x3B {
+ if value[i] < '!' || value[i] > '~' || value[i] == ';' {
return false
}
}
diff --git a/vendor/github.com/lrstanley/girc/client.go b/vendor/github.com/lrstanley/girc/client.go
index 403a7aec..501554b9 100644
--- a/vendor/github.com/lrstanley/girc/client.go
+++ b/vendor/github.com/lrstanley/girc/client.go
@@ -464,9 +464,9 @@ func (c *Client) GetHost() string {
return c.state.host
}
-// Channels returns the active list of channels that the client is in.
+// ChannelList returns the active list of channel names that the client is in.
// Panics if tracking is disabled.
-func (c *Client) Channels() []string {
+func (c *Client) ChannelList() []string {
c.panicIfNotTracking()
c.state.RLock()
@@ -482,9 +482,26 @@ func (c *Client) Channels() []string {
return channels
}
-// Users returns the active list of users that the client is tracking across
-// all files. Panics if tracking is disabled.
-func (c *Client) Users() []string {
+// Channels returns the active channels that the client is in. Panics if
+// tracking is disabled.
+func (c *Client) Channels() []*Channel {
+ c.panicIfNotTracking()
+
+ c.state.RLock()
+ channels := make([]*Channel, len(c.state.channels))
+ var i int
+ for channel := range c.state.channels {
+ channels[i] = c.state.channels[channel].Copy()
+ i++
+ }
+ c.state.RUnlock()
+
+ return channels
+}
+
+// UserList returns the active list of nicknames that the client is tracking
+// across all networks. Panics if tracking is disabled.
+func (c *Client) UserList() []string {
c.panicIfNotTracking()
c.state.RLock()
@@ -500,6 +517,23 @@ func (c *Client) Users() []string {
return users
}
+// Users returns the active users that the client is tracking across all
+// networks. Panics if tracking is disabled.
+func (c *Client) Users() []*User {
+ c.panicIfNotTracking()
+
+ c.state.RLock()
+ users := make([]*User, len(c.state.users))
+ var i int
+ for user := range c.state.users {
+ users[i] = c.state.users[user].Copy()
+ i++
+ }
+ c.state.RUnlock()
+
+ return users
+}
+
// LookupChannel looks up a given channel in state. If the channel doesn't
// exist, nil is returned. Panics if tracking is disabled.
func (c *Client) LookupChannel(name string) *Channel {
diff --git a/vendor/github.com/lrstanley/girc/commands.go b/vendor/github.com/lrstanley/girc/commands.go
index 3f7d3bdc..d22f7616 100644
--- a/vendor/github.com/lrstanley/girc/commands.go
+++ b/vendor/github.com/lrstanley/girc/commands.go
@@ -272,6 +272,27 @@ func (cmd *Commands) Kick(channel, user, reason string) {
cmd.c.Send(&Event{Command: KICK, Params: []string{channel, user}})
}
+// Ban adds the +b mode on the given mask on a channel.
+func (cmd *Commands) Ban(channel, mask string) {
+ cmd.Mode(channel, "+b", mask)
+}
+
+// Unban removes the +b mode on the given mask on a channel.
+func (cmd *Commands) Unban(channel, mask string) {
+ cmd.Mode(channel, "-b", mask)
+}
+
+// Mode sends a mode change to the server which should be applied to target
+// (usually a channel or user), along with a set of modes (generally "+m",
+// "+mmmm", or "-m", where "m" is the mode you want to change). Params is only
+// needed if the mode change requires a parameter (ban or invite-only exclude.)
+func (cmd *Commands) Mode(target, modes string, params ...string) {
+ out := []string{target, modes}
+ out = append(out, params...)
+
+ cmd.c.Send(&Event{Command: MODE, Params: out})
+}
+
// Invite sends a INVITE query to the server, to invite nick to channel.
func (cmd *Commands) Invite(channel string, users ...string) {
for i := 0; i < len(users); i++ {
diff --git a/vendor/github.com/lrstanley/girc/ctcp.go b/vendor/github.com/lrstanley/girc/ctcp.go
index c6c0bace..6076ab10 100644
--- a/vendor/github.com/lrstanley/girc/ctcp.go
+++ b/vendor/github.com/lrstanley/girc/ctcp.go
@@ -58,7 +58,7 @@ func decodeCTCP(e *Event) *CTCPEvent {
if s < 0 {
for i := 0; i < len(text); i++ {
// Check for A-Z, 0-9.
- if (text[i] < 0x41 || text[i] > 0x5A) && (text[i] < 0x30 || text[i] > 0x39) {
+ if (text[i] < 'A' || text[i] > 'Z') && (text[i] < '0' || text[i] > '9') {
return nil
}
}
@@ -74,7 +74,7 @@ func decodeCTCP(e *Event) *CTCPEvent {
// Loop through checking the tag first.
for i := 0; i < s; i++ {
// Check for A-Z, 0-9.
- if (text[i] < 0x41 || text[i] > 0x5A) && (text[i] < 0x30 || text[i] > 0x39) {
+ if (text[i] < 'A' || text[i] > 'Z') && (text[i] < '0' || text[i] > '9') {
return nil
}
}
@@ -168,7 +168,7 @@ func (c *CTCP) parseCMD(cmd string) string {
for i := 0; i < len(cmd); i++ {
// Check for A-Z, 0-9.
- if (cmd[i] < 0x41 || cmd[i] > 0x5A) && (cmd[i] < 0x30 || cmd[i] > 0x39) {
+ if (cmd[i] < 'A' || cmd[i] > 'Z') && (cmd[i] < '0' || cmd[i] > '9') {
return ""
}
}
diff --git a/vendor/github.com/lrstanley/girc/event.go b/vendor/github.com/lrstanley/girc/event.go
index 77d9b45e..ef7209ed 100644
--- a/vendor/github.com/lrstanley/girc/event.go
+++ b/vendor/github.com/lrstanley/girc/event.go
@@ -11,8 +11,8 @@ import (
)
const (
- eventSpace byte = 0x20 // Separator.
- maxLength = 510 // Maximum length is 510 (2 for line endings).
+ eventSpace byte = ' ' // Separator.
+ maxLength = 510 // Maximum length is 510 (2 for line endings).
)
// cutCRFunc is used to trim CR characters from prefixes/messages.
@@ -256,7 +256,7 @@ func (e *Event) Bytes() []byte {
// Strip newlines and carriage returns.
for i := 0; i < len(out); i++ {
- if out[i] == 0x0A || out[i] == 0x0D {
+ if out[i] == '\n' || out[i] == '\r' {
out = append(out[:i], out[i+1:]...)
i-- // Decrease the index so we can pick up where we left off.
}
@@ -432,9 +432,9 @@ func (e *Event) StripAction() string {
}
const (
- messagePrefix byte = 0x3A // ":" -- prefix or last argument
- prefixIdent byte = 0x21 // "!" -- username
- prefixHost byte = 0x40 // "@" -- hostname
+ messagePrefix byte = ':' // Prefix or last argument.
+ prefixIdent byte = '!' // Username.
+ prefixHost byte = '@' // Hostname.
)
// Source represents the sender of an IRC event, see RFC1459 section 2.3.1.
diff --git a/vendor/github.com/lrstanley/girc/format.go b/vendor/github.com/lrstanley/girc/format.go
index 5e3b5a6a..78a1f7bb 100644
--- a/vendor/github.com/lrstanley/girc/format.go
+++ b/vendor/github.com/lrstanley/girc/format.go
@@ -12,8 +12,8 @@ import (
)
const (
- fmtOpenChar = 0x7B // {
- fmtCloseChar = 0x7D // }
+ fmtOpenChar = '{'
+ fmtCloseChar = '}'
)
var fmtColors = map[string]int{
@@ -113,7 +113,7 @@ func Fmt(text string) string {
if last > -1 {
// A-Z, a-z, and ","
- if text[i] != 0x2c && (text[i] <= 0x41 || text[i] >= 0x5a) && (text[i] <= 0x61 || text[i] >= 0x7a) {
+ if text[i] != ',' && (text[i] <= 'A' || text[i] >= 'Z') && (text[i] <= 'a' || text[i] >= 'z') {
last = -1
continue
}
@@ -127,10 +127,10 @@ func Fmt(text string) string {
// See Fmt() for more information.
func TrimFmt(text string) string {
for color := range fmtColors {
- text = strings.Replace(text, "{"+color+"}", "", -1)
+ text = strings.Replace(text, string(fmtOpenChar)+color+string(fmtCloseChar), "", -1)
}
for code := range fmtCodes {
- text = strings.Replace(text, "{"+code+"}", "", -1)
+ text = strings.Replace(text, string(fmtOpenChar)+code+string(fmtCloseChar), "", -1)
}
return text
@@ -175,9 +175,10 @@ func IsValidChannel(channel string) bool {
return false
}
- // #, +, !<channelid>, or &
- // Including "*" in the prefix list, as this is commonly used (e.g. ZNC)
- if bytes.IndexByte([]byte{0x21, 0x23, 0x26, 0x2A, 0x2B}, channel[0]) == -1 {
+ // #, +, !<channelid>, ~, or &
+ // Including "*" and "~" in the prefix list, as these are commonly used
+ // (e.g. ZNC.)
+ if bytes.IndexByte([]byte{'!', '#', '&', '*', '~', '+'}, channel[0]) == -1 {
return false
}
@@ -186,14 +187,14 @@ func IsValidChannel(channel string) bool {
// 1 (prefix) + 5 (id) + 1 (+, channel name)
// On some networks, this may be extended with ISUPPORT capabilities,
// however this is extremely uncommon.
- if channel[0] == 0x21 {
+ if channel[0] == '!' {
if len(channel) < 7 {
return false
}
// check for valid ID
for i := 1; i < 6; i++ {
- if (channel[i] < 0x30 || channel[i] > 0x39) && (channel[i] < 0x41 || channel[i] > 0x5A) {
+ if (channel[i] < '0' || channel[i] > '9') && (channel[i] < 'A' || channel[i] > 'Z') {
return false
}
}
@@ -222,18 +223,15 @@ func IsValidNick(nick string) bool {
return false
}
- nick = ToRFC1459(nick)
-
// Check the first index. Some characters aren't allowed for the first
// index of an IRC nickname.
- if nick[0] < 0x41 || nick[0] > 0x7D {
- // a-z, A-Z, and _\[]{}^|
+ if (nick[0] < 'A' || nick[0] > '}') && nick[0] != '?' {
+ // a-z, A-Z, '_\[]{}^|', and '?' in the case of znc.
return false
}
for i := 1; i < len(nick); i++ {
- if (nick[i] < 0x41 || nick[i] > 0x7E) && (nick[i] < 0x30 || nick[i] > 0x39) && nick[i] != 0x2D {
- fmt.Println(nick[i], i, nick)
+ if (nick[i] < 'A' || nick[i] > '}') && (nick[i] < '0' || nick[i] > '9') && nick[i] != '-' {
// a-z, A-Z, 0-9, -, and _\[]{}^|
return false
}
@@ -262,10 +260,8 @@ func IsValidUser(name string) bool {
return false
}
- name = ToRFC1459(name)
-
// "~" is prepended (commonly) if there was no ident server response.
- if name[0] == 0x7E {
+ if name[0] == '~' {
// Means name only contained "~".
if len(name) < 2 {
return false
@@ -275,12 +271,12 @@ func IsValidUser(name string) bool {
}
// Check to see if the first index is alphanumeric.
- if (name[0] < 0x41 || name[0] > 0x4A) && (name[0] < 0x61 || name[0] > 0x7A) && (name[0] < 0x30 || name[0] > 0x39) {
+ if (name[0] < 'A' || name[0] > 'J') && (name[0] < 'a' || name[0] > 'z') && (name[0] < '0' || name[0] > '9') {
return false
}
for i := 1; i < len(name); i++ {
- if (name[i] < 0x41 || name[i] > 0x7D) && (name[i] < 0x30 || name[i] > 0x39) && name[i] != 0x2D && name[i] != 0x2E {
+ if (name[i] < 'A' || name[i] > '}') && (name[i] < '0' || name[i] > '9') && name[i] != '-' && name[i] != '.' {
// a-z, A-Z, 0-9, -, and _\[]{}^|
return false
}
@@ -291,7 +287,10 @@ func IsValidUser(name string) bool {
// ToRFC1459 converts a string to the stripped down conversion within RFC
// 1459. This will do things like replace an "A" with an "a", "[]" with "{}",
-// and so forth. Useful to compare two nicknames or channels.
+// and so forth. Useful to compare two nicknames or channels. Note that this
+// should not be used to normalize nicknames or similar, as this may convert
+// valid input characters to non-rfc-valid characters. As such, it's main use
+// is for comparing two nicks.
func ToRFC1459(input string) string {
var out string
diff --git a/vendor/github.com/lrstanley/girc/handler.go b/vendor/github.com/lrstanley/girc/handler.go
index f0c737f2..6c082708 100644
--- a/vendor/github.com/lrstanley/girc/handler.go
+++ b/vendor/github.com/lrstanley/girc/handler.go
@@ -29,11 +29,12 @@ func (c *Client) RunHandlers(event *Event) {
}
}
- // Regular wildcard handlers.
- c.Handlers.exec(ALL_EVENTS, c, event.Copy())
+ // Background handlers first.
+ c.Handlers.exec(ALL_EVENTS, true, c, event.Copy())
+ c.Handlers.exec(event.Command, true, c, event.Copy())
- // Then regular handlers.
- c.Handlers.exec(event.Command, c, event.Copy())
+ c.Handlers.exec(ALL_EVENTS, false, c, event.Copy())
+ c.Handlers.exec(event.Command, false, c, event.Copy())
// Check if it's a CTCP.
if ctcp := decodeCTCP(event.Copy()); ctcp != nil {
@@ -144,7 +145,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 handler maps.
func (c *Caller) cuidToID(input string) (cmd, uid string) {
- i := strings.IndexByte(input, 0x3A)
+ i := strings.IndexByte(input, ':')
if i < 0 {
return "", ""
}
@@ -160,9 +161,9 @@ type execStack struct {
// exec executes all handlers pertaining to specified event. Internal first,
// then external.
//
-// Please note that there is no specific order/priority for which the
-// handler types themselves or the handlers are executed.
-func (c *Caller) exec(command string, client *Client, event *Event) {
+// Please note that there is no specific order/priority for which the handlers
+// are executed.
+func (c *Caller) exec(command string, bg bool, client *Client, event *Event) {
// Build a stack of handlers which can be executed concurrently.
var stack []execStack
@@ -170,13 +171,21 @@ func (c *Caller) exec(command string, client *Client, event *Event) {
// Get internal handlers first.
if _, ok := c.internal[command]; ok {
for cuid := range c.internal[command] {
+ if (strings.HasSuffix(cuid, ":bg") && !bg) || (!strings.HasSuffix(cuid, ":bg") && bg) {
+ continue
+ }
+
stack = append(stack, execStack{c.internal[command][cuid], cuid})
}
}
- // Aaand then external handlers.
+ // Then external handlers.
if _, ok := c.external[command]; ok {
for cuid := range c.external[command] {
+ if (strings.HasSuffix(cuid, ":bg") && !bg) || (!strings.HasSuffix(cuid, ":bg") && bg) {
+ continue
+ }
+
stack = append(stack, execStack{c.external[command][cuid], cuid})
}
}
@@ -189,18 +198,29 @@ func (c *Caller) exec(command string, client *Client, event *Event) {
wg.Add(len(stack))
for i := 0; i < len(stack); i++ {
go func(index int) {
- c.debug.Printf("executing handler %s for event %s (%d of %d)", stack[index].cuid, command, index+1, len(stack))
+ defer wg.Done()
+ c.debug.Printf("[%d/%d] exec %s => %s", index+1, len(stack), stack[index].cuid, command)
start := time.Now()
- // If they want to catch any panics, add to defer stack.
+ if bg {
+ go func() {
+ if client.Config.RecoverFunc != nil {
+ defer recoverHandlerPanic(client, event, stack[index].cuid, 3)
+ }
+
+ stack[index].Execute(client, *event)
+ c.debug.Printf("[%d/%d] done %s == %s", index+1, len(stack), stack[index].cuid, time.Since(start))
+ }()
+
+ return
+ }
+
if client.Config.RecoverFunc != nil {
defer recoverHandlerPanic(client, event, stack[index].cuid, 3)
}
stack[index].Execute(client, *event)
-
- c.debug.Printf("execution of %s took %s (%d of %d)", stack[index].cuid, time.Since(start), index+1, len(stack))
- wg.Done()
+ c.debug.Printf("[%d/%d] done %s == %s", index+1, len(stack), stack[index].cuid, time.Since(start))
}(i)
}
@@ -281,9 +301,9 @@ 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, handler Handler) (cuid string) {
+func (c *Caller) sregister(internal, bg bool, cmd string, handler Handler) (cuid string) {
c.mu.Lock()
- cuid = c.register(internal, cmd, handler)
+ cuid = c.register(internal, bg, cmd, handler)
c.mu.Unlock()
return cuid
@@ -291,30 +311,34 @@ func (c *Caller) sregister(internal bool, cmd string, handler Handler) (cuid str
// register will register a handler in the internal tracker. Unsafe (you
// must lock c.mu yourself!)
-func (c *Caller) register(internal bool, cmd string, handler Handler) (cuid string) {
+func (c *Caller) register(internal, bg bool, cmd string, handler Handler) (cuid string) {
var uid string
cmd = strings.ToUpper(cmd)
+ cuid, uid = c.cuid(cmd, 20)
+ if bg {
+ uid += ":bg"
+ cuid += ":bg"
+ }
+
if internal {
if _, ok := c.internal[cmd]; !ok {
c.internal[cmd] = map[string]Handler{}
}
- cuid, uid = c.cuid(cmd, 20)
c.internal[cmd][uid] = handler
} else {
if _, ok := c.external[cmd]; !ok {
c.external[cmd] = map[string]Handler{}
}
- cuid, uid = c.cuid(cmd, 20)
c.external[cmd][uid] = handler
}
_, file, line, _ := runtime.Caller(3)
- c.debug.Printf("registering handler for %q with cuid %q (internal: %t) from: %s:%d", cmd, cuid, internal, file, line)
+ c.debug.Printf("reg %q => %s [int:%t bg:%t] %s:%d", uid, cmd, internal, bg, file, line)
return cuid
}
@@ -323,31 +347,20 @@ func (c *Caller) register(internal bool, cmd string, handler Handler) (cuid stri
// 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)
+ return c.sregister(false, false, cmd, handler)
}
// 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(client *Client, event Event)) (cuid string) {
- return c.sregister(false, cmd, HandlerFunc(handler))
+ return c.sregister(false, false, cmd, HandlerFunc(handler))
}
// 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(client *Client, event Event)) (cuid string) {
- return c.sregister(false, cmd, HandlerFunc(func(client *Client, event Event) {
- // Setting up background-based handlers this way allows us to get
- // clean call stacks for use with panic recovery.
- go func() {
- // If they want to catch any panics, add to defer stack.
- if client.Config.RecoverFunc != nil {
- defer recoverHandlerPanic(client, &event, "goroutine", 3)
- }
-
- handler(client, event)
- }()
- }))
+ return c.sregister(false, true, cmd, HandlerFunc(handler))
}
// AddTmp adds a "temporary" handler, which is good for one-time or few-time
@@ -361,47 +374,37 @@ func (c *Caller) AddBg(cmd string, handler func(client *Client, event Event)) (c
//
// Additionally, AddTmp has a useful option, deadline. When set to greater
// than 0, deadline will be the amount of time that passes before the handler
-// is removed from the stack, regardless if the handler returns true or not.
+// is removed from the stack, regardless of if the handler returns true or not.
// This is useful in that it ensures that the handler is cleaned up if the
// server does not respond appropriately, or takes too long to respond.
//
// Note that handlers supplied with AddTmp are executed in a goroutine to
-// ensure that they are not blocking other handlers. Additionally, use cuid
-// with Caller.Remove() to prematurely remove the handler from the stack,
-// bypassing the timeout or waiting for the handler to return that it wants
-// to be removed from the stack.
+// ensure that they are not blocking other handlers. However, if you are
+// creating a temporary handler from another handler, it should be a
+// background handler.
+//
+// Use cuid with Caller.Remove() to prematurely remove the handler from the
+// stack, bypassing the timeout or waiting for the handler to return that it
+// wants to be removed from the stack.
func (c *Caller) AddTmp(cmd string, deadline time.Duration, handler func(client *Client, event Event) bool) (cuid string, done chan struct{}) {
- var uid string
- cuid, uid = c.cuid(cmd, 20)
-
done = make(chan struct{})
- c.mu.Lock()
- if _, ok := c.external[cmd]; !ok {
- c.external[cmd] = map[string]Handler{}
- }
- c.external[cmd][uid] = HandlerFunc(func(client *Client, event Event) {
- // Setting up background-based handlers this way allows us to get
- // clean call stacks for use with panic recovery.
- go func() {
- // If they want to catch any panics, add to defer stack.
- if client.Config.RecoverFunc != nil {
- defer recoverHandlerPanic(client, &event, "tmp-goroutine", 3)
- }
-
- remove := handler(client, event)
- if remove {
- if ok := c.Remove(cuid); ok {
- close(done)
- }
+ cuid = c.sregister(false, true, cmd, HandlerFunc(func(client *Client, event Event) {
+ remove := handler(client, event)
+ if remove {
+ if ok := c.Remove(cuid); ok {
+ close(done)
}
- }()
- })
- c.mu.Unlock()
+ }
+ }))
if deadline > 0 {
go func() {
- <-time.After(deadline)
+ select {
+ case <-time.After(deadline):
+ case <-done:
+ }
+
if ok := c.Remove(cuid); ok {
close(done)
}
diff --git a/vendor/github.com/lrstanley/girc/modes.go b/vendor/github.com/lrstanley/girc/modes.go
index c0ad7d11..864df71f 100644
--- a/vendor/github.com/lrstanley/girc/modes.go
+++ b/vendor/github.com/lrstanley/girc/modes.go
@@ -206,11 +206,11 @@ func (c *CModes) Parse(flags string, args []string) (out []CMode) {
var argCount int
for i := 0; i < len(flags); i++ {
- if flags[i] == 0x2B {
+ if flags[i] == '+' {
add = true
continue
}
- if flags[i] == 0x2D {
+ if flags[i] == '-' {
add = false
continue
}
@@ -265,7 +265,7 @@ func IsValidChannelMode(raw string) bool {
for i := 0; i < len(raw); i++ {
// Allowed are: ",", A-Z and a-z.
- if raw[i] != 0x2C && (raw[i] < 0x41 || raw[i] > 0x5A) && (raw[i] < 0x61 || raw[i] > 0x7A) {
+ if raw[i] != ',' && (raw[i] < 'A' || raw[i] > 'Z') && (raw[i] < 'a' || raw[i] > 'z') {
return false
}
}
@@ -279,7 +279,7 @@ func isValidUserPrefix(raw string) bool {
return false
}
- if raw[0] != 0x28 { // (.
+ if raw[0] != '(' {
return false
}
@@ -288,7 +288,7 @@ func isValidUserPrefix(raw string) bool {
// Skip the first one as we know it's (.
for i := 1; i < len(raw); i++ {
- if raw[i] == 0x29 { // ).
+ if raw[i] == ')' {
passedKeys = true
continue
}
diff --git a/vendor/manifest b/vendor/manifest
index 680cc709..98dcbd0e 100644
--- a/vendor/manifest
+++ b/vendor/manifest
@@ -282,7 +282,7 @@
"importpath": "github.com/lrstanley/girc",
"repository": "https://github.com/lrstanley/girc",
"vcs": "git",
- "revision": "e698f0468e166574e122130ffd2f579aba7e2abc",
+ "revision": "5dff93b5453c1b2ac8382c9a38881635f47bba0e",
"branch": "master",
"notests": true
},