Skip to content
This repository has been archived by the owner on Mar 11, 2024. It is now read-only.

Allow Protocol Argument Passing #112

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
65 changes: 57 additions & 8 deletions bot.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,18 +55,30 @@ type Config struct {
type responseMessage struct {
target, message string
sender *User
protoParams interface{}
}

type OutgoingMessage struct {
fabioxgn marked this conversation as resolved.
Show resolved Hide resolved
fabioxgn marked this conversation as resolved.
Show resolved Hide resolved
Target string
Message string
Sender *User
ProtoParams interface{}
}

// ResponseHandler must be implemented by the protocol to handle the bot responses
type ResponseHandler func(target, message string, sender *User)

// ResponseHandlerV2 may be implemented by the protocol to handle the bot responses
type ResponseHandlerV2 func(OutgoingMessage)

// ErrorHandler will be called when an error happens
type ErrorHandler func(msg string, err error)

// Handlers that must be registered to receive callbacks from the bot
type Handlers struct {
Response ResponseHandler
Errored ErrorHandler
Response ResponseHandler
ResponseV2 ResponseHandlerV2
Errored ErrorHandler
}

func logErrorHandler(msg string, err error) {
Expand Down Expand Up @@ -158,7 +170,7 @@ 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) {
command, err := parse(message.Text, channel, sender)
command, err := parse(message, channel, sender)
if err != nil {
b.SendMessage(channel.Channel, err.Error(), sender)
return
Expand Down Expand Up @@ -192,20 +204,57 @@ func (b *Bot) SendMessage(target string, message string, sender *User) {
message = b.executeFilterCommands(&FilterCmd{
Target: target,
Message: message,
User: sender})
User: sender,
})
if message == "" {
return
}

select {
case b.msgsToSend <- responseMessage{target, message, sender}:
case b.msgsToSend <- responseMessage{
target: target,
message: message,
sender: sender,
}:
default:
b.errored("Failed to queue message to send.", errors.New("Too busy"))
}
}

func (b *Bot) sendResponse(target, message string, sender *User) {
b.handlers.Response(target, message, sender)
// SendMessage queues a message for a target recipient, optionally from a particular sender.
fabioxgn marked this conversation as resolved.
Show resolved Hide resolved
fabioxgn marked this conversation as resolved.
Show resolved Hide resolved
func (b *Bot) SendMessageV2(om OutgoingMessage) {
message := b.executeFilterCommands(&FilterCmd{
Target: om.Target,
Message: om.Message,
User: om.Sender,
})
if message == "" {
return
}

select {
case b.msgsToSend <- responseMessage{
target: om.Target,
message: om.Message,
sender: om.Sender,
protoParams: om.ProtoParams,
}:
default:
b.errored("Failed to queue message to send.", errors.New("Too busy"))
}
}

func (b *Bot) sendResponse(resp responseMessage) {
if b.handlers.ResponseV2 != nil {
b.handlers.ResponseV2(OutgoingMessage{
Message: resp.message,
ProtoParams: resp.protoParams,
Sender: resp.sender,
Target: resp.target,
})
return
}
b.handlers.Response(resp.target, resp.message, resp.sender)
}

func (b *Bot) errored(msg string, err error) {
Expand All @@ -218,7 +267,7 @@ func (b *Bot) processMessages() {
for {
select {
case msg := <-b.msgsToSend:
b.sendResponse(msg.target, msg.message, msg.sender)
b.sendResponse(msg)
case <-b.done:
return
}
Expand Down
31 changes: 22 additions & 9 deletions cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,9 @@ 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
IsAction bool // True if this was a '/me does something' message
Text string // The actual content of this Message
IsAction bool // True if this was a '/me does something' message
ProtoMsg interface{} // The underlying object that we got from the protocol pkg
}

// FilterCmd holds information about what is output being filtered - message and
Expand Down Expand Up @@ -108,15 +109,17 @@ type customCommand struct {

// CmdResult is the result message of V2 commands
type CmdResult struct {
Channel string // The channel where the bot should send the message
Message string // The message to be sent
Channel string // The channel where the bot should send the message
Message string // The message to be sent
ProtoParams interface{}
}

// CmdResultV3 is the result message of V3 commands
type CmdResultV3 struct {
Channel string
Message chan string
Done chan bool
Channel string
Message chan string
Done chan bool
ProtoParams interface{}
}

const (
Expand Down Expand Up @@ -389,7 +392,12 @@ func (b *Bot) handleCmd(c *Cmd) {
}

if result.Message != "" {
b.SendMessage(result.Channel, result.Message, c.User)
b.SendMessageV2(OutgoingMessage{
Target: result.Channel,
Message: result.Message,
Sender: c.User,
ProtoParams: result.ProtoParams,
})
}
case v3:
result, err := cmd.CmdFuncV3(c)
Expand All @@ -401,7 +409,12 @@ func (b *Bot) handleCmd(c *Cmd) {
select {
case message := <-result.Message:
if message != "" {
b.SendMessage(result.Channel, message, c.User)
b.SendMessageV2(OutgoingMessage{
Target: result.Channel,
Message: message,
Sender: c.User,
ProtoParams: result.ProtoParams,
})
}
case <-result.Done:
return
Expand Down
5 changes: 4 additions & 1 deletion help.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ const (
)

func (b *Bot) help(c *Cmd) {
cmd, _ := parse(CmdPrefix+c.RawArgs, c.ChannelData, c.User)
msg := &Message{
Text: CmdPrefix + c.RawArgs,
}
cmd, _ := parse(msg, c.ChannelData, c.User)
if cmd == nil {
b.showAvailabeCommands(c.Channel, c.User)
return
Expand Down
24 changes: 11 additions & 13 deletions parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,20 @@ var (
re = regexp.MustCompile("\\s+") // Matches one or more spaces
)

func parse(s string, channel *ChannelData, user *User) (*Cmd, error) {
c := &Cmd{Raw: s}
s = strings.TrimSpace(s)
func parse(m *Message, channel *ChannelData, user *User) (*Cmd, error) {
s := strings.TrimSpace(m.Text)

if !strings.HasPrefix(s, CmdPrefix) {
return nil, nil
}

c.Channel = strings.TrimSpace(channel.Channel)
c.ChannelData = channel
c.User = user

// Trim the prefix and extra spaces
c.Message = strings.TrimPrefix(s, CmdPrefix)
c.Message = strings.TrimSpace(c.Message)
c := &Cmd{
Channel: strings.TrimSpace(channel.Channel),
ChannelData: channel,
Message: strings.TrimSpace(strings.TrimPrefix(s, CmdPrefix)),
Raw: m.Text,
User: user,
}

// check if we have the command and not only the prefix
if c.Message == "" {
Expand All @@ -48,9 +47,8 @@ func parse(s string, channel *ChannelData, user *User) (*Cmd, error) {
c.Args = parsedArgs
}

c.MessageData = &Message{
Text: c.Message,
}
m.Text = c.Message
c.MessageData = m

return c, nil
}
65 changes: 44 additions & 21 deletions slack/slack.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,26 @@ func defaultMessageFilter(message string, _ *bot.User) (string, slack.PostMessag

func responseHandler(target string, message string, sender *bot.User) {
message, params := messageFilter(message, sender)
_, _, err := api.PostMessage(target, slack.MsgOptionPostMessageParameters(params),
slack.MsgOptionText(message, false))
_, _, err := api.PostMessage(
target,
slack.MsgOptionPostMessageParameters(params),
slack.MsgOptionText(message, false),
)
if err != nil {
fmt.Printf("Error sending a slack message: %s\n", err.Error())
}
}

func responseHandlerV2(om bot.OutgoingMessage) {
message, params := messageFilter(om.Message, om.Sender)
if pmp, ok := om.ProtoParams.(*slack.PostMessageParameters); ok {
params = *pmp
}
_, _, err := api.PostMessage(
om.Target,
slack.MsgOptionPostMessageParameters(params),
slack.MsgOptionText(message, false),
)
if err != nil {
fmt.Printf("Error sending a slack message: %s\n", err.Error())
}
Expand Down Expand Up @@ -74,7 +92,9 @@ func extractUser(event *slack.MessageEvent) *bot.User {
}

func extractText(event *slack.MessageEvent) *bot.Message {
msg := &bot.Message{}
msg := &bot.Message{
ProtoMsg: event,
}
if len(event.Text) != 0 {
msg.Text = event.Text
if event.SubType == "me_message" {
Expand Down Expand Up @@ -130,7 +150,8 @@ func Run(token string) {
teaminfo, _ = api.GetTeamInfo()

b := bot.New(&bot.Handlers{
Response: responseHandler,
Response: responseHandler,
ResponseV2: responseHandlerV2,
},
&bot.Config{
Protocol: protocol,
Expand All @@ -156,24 +177,26 @@ Loop:
readChannelData(api)

case *slack.MessageEvent:
if !ev.Hidden && !ownMessage(ev.User) {
C := channelList[ev.Channel]
var channel = ev.Channel
if C.IsChannel {
channel = fmt.Sprintf("#%s", C.Name)
}
go b.MessageReceived(
&bot.ChannelData{
Protocol: "slack",
Server: teaminfo.Domain,
Channel: channel,
HumanName: C.Name,
IsPrivate: !C.IsChannel,
},
extractText(ev),
extractUser(ev),
)
if ev.Hidden || ownMessage(ev.User) {
continue
}

C := channelList[ev.Channel]
var channel = ev.Channel
if C.IsChannel {
channel = fmt.Sprintf("#%s", C.Name)
}
go b.MessageReceived(
&bot.ChannelData{
Protocol: protocol,
Server: teaminfo.Domain,
Channel: channel,
HumanName: C.Name,
IsPrivate: !C.IsChannel,
},
extractText(ev),
extractUser(ev),
)

case *slack.RTMError:
fmt.Printf("Error: %s\n", ev.Error())
Expand Down