Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions bot.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"log"
"math/rand"
"time"
"strings"

"github.com/robfig/cron"
)
Expand Down Expand Up @@ -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)
Expand Down
46 changes: 46 additions & 0 deletions cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand All @@ -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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down
19 changes: 19 additions & 0 deletions irc/irc.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down