diff --git a/bot.go b/bot.go index c33cd72..318faf1 100644 --- a/bot.go +++ b/bot.go @@ -5,6 +5,7 @@ import ( "log" "math/rand" "time" + "strings" "github.com/robfig/cron" ) @@ -62,6 +63,16 @@ func (b *Bot) startPeriodicCommands() { // MessageReceived must be called by the protocol upon receiving a message func (b *Bot) MessageReceived(channel *ChannelData, message *Message, sender *User) { + if message.Text == "" { + b.ExecuteEventCommands(&EventCmd{ + EventCode: message.EventCode, + Channel: strings.TrimSpace(channel.Channel), + ChannelData: channel, + User: sender, + }) + return + } + command, err := parse(message.Text, channel, sender) if err != nil { b.handlers.Response(channel.Channel, err.Error(), sender) diff --git a/cmd.go b/cmd.go index 418c1f6..b66a98b 100644 --- a/cmd.go +++ b/cmd.go @@ -35,6 +35,7 @@ func (c *ChannelData) URI() string { // Message holds the message info - for IRC and Slack networks, this can include whether the message was an action. type Message struct { Text string // The actual content of this Message + EventCode string // Event that triggered this message to happen (protocol specific) IsAction bool // True if this was a '/me does something' message } @@ -47,6 +48,13 @@ type PassiveCmd struct { User *User // User who sent this message } +type EventCmd struct { + EventCode string // Which event code has actually occured + Channel string // Channel wich the message was sent to + ChannelData *ChannelData // Channel and network info + User *User // User who sent this message +} + // PeriodicConfig holds a cron specification for periodically notifying the configured channels type PeriodicConfig struct { CronSpec string // CronSpec that schedules some function @@ -91,11 +99,13 @@ const ( type passiveCmdFunc func(cmd *PassiveCmd) (string, error) type activeCmdFuncV1 func(cmd *Cmd) (string, error) type activeCmdFuncV2 func(cmd *Cmd) (CmdResult, error) +type eventCmdFunc func(cmd *EventCmd) (string, error) var ( commands = make(map[string]*customCommand) passiveCommands = make(map[string]passiveCmdFunc) periodicCommands = make(map[string]PeriodicConfig) + eventCommands = make(map[string]eventCmdFunc) ) // RegisterCommand adds a new command to the bot. @@ -135,6 +145,14 @@ func RegisterPassiveCommand(command string, cmdFunc func(cmd *PassiveCmd) (strin passiveCommands[command] = cmdFunc } +// RegisterEventCommand adds a new passive command to the bot. +// The command should be registered in the Init() func of your package +// command: String which the user will use to add some behavior in some irc event +// cmdFunc: Function which will be executed once the irc event occurs +func RegisterEventCommand(command string, cmdFunc eventCmdFunc) { + eventCommands[command] = cmdFunc +} + // RegisterPeriodicCommand adds a command that is run periodically. // The command should be registered in the Init() func of your package // config: PeriodicConfig which specify CronSpec and a channel list @@ -178,6 +196,34 @@ func (b *Bot) executePassiveCommands(cmd *PassiveCmd) { wg.Wait() } +func (b *Bot) ExecuteEventCommands(cmd *EventCmd) { + var wg sync.WaitGroup + mutex := &sync.Mutex{} + + for k, v := range eventCommands { + if b.isDisabled(k) { + continue + } + + cmdFunc := v + wg.Add(1) + + go func() { + defer wg.Done() + + result, err := cmdFunc(cmd) + if err != nil { + log.Println(err) + } else { + mutex.Lock() + b.handlers.Response(cmd.Channel, result, cmd.User) + mutex.Unlock() + } + }() + } + wg.Wait() +} + func (b *Bot) isDisabled(cmd string) bool { for _, c := range b.disabledCmds { if c == cmd { diff --git a/irc/irc.go b/irc/irc.go index 50e097c..ddb3e7e 100644 --- a/irc/irc.go +++ b/irc/irc.go @@ -74,6 +74,24 @@ func onCTCPACTION(e *ircevent.Event) { }) } +func onJOIN(e *ircevent.Event) { + b.MessageReceived( + &bot.ChannelData{ + Protocol: "irc", + Server: ircConn.Server, + Channel: e.Arguments[0], + IsPrivate: false, + }, + &bot.Message{ + EventCode: e.Code, + }, + &bot.User{ + ID: e.Host, + Nick: e.Nick, + RealName: e.User, + }) +} + func getServerName(server string) string { separatorIndex := strings.LastIndex(server, ":") if separatorIndex != -1 { @@ -108,6 +126,7 @@ func Run(c *Config) { ircConn.AddCallback("001", onWelcome) ircConn.AddCallback("PRIVMSG", onPRIVMSG) ircConn.AddCallback("CTCP_ACTION", onCTCPACTION) + ircConn.AddCallback("JOIN", onJOIN) err := ircConn.Connect(c.Server) if err != nil {