From 34e2404e8bb68d281be77a174c6f7df3393d03b8 Mon Sep 17 00:00:00 2001 From: Scott Kiesel Date: Tue, 31 Oct 2017 06:22:36 -0400 Subject: [PATCH 1/8] hacked poc for edits as an animation mechanism --- bot/bot.go | 6 +- bot/handlers.go | 6 ++ bot/interfaces.go | 3 + bot/mock.go | 2 + irc/irc.go | 4 ++ main.go | 2 + plugins/rpgORdie/rpgORdie.go | 61 +++++++++++++++++++ plugins/rpgORdie/rpgORdie_test.go | 4 ++ slack/slack.go | 98 +++++++++++++++++++++++++++---- 9 files changed, 175 insertions(+), 11 deletions(-) create mode 100644 plugins/rpgORdie/rpgORdie.go create mode 100644 plugins/rpgORdie/rpgORdie_test.go diff --git a/bot/bot.go b/bot/bot.go index 873d361..2507586 100644 --- a/bot/bot.go +++ b/bot/bot.go @@ -110,6 +110,10 @@ func (b *bot) DB() *sqlx.DB { return b.db } +func (b *bot) Conn() Connector { + return b.conn +} + // Create any tables if necessary based on version of DB // Plugins should create their own tables, these are only for official bot stuff // Note: This does not return an error. Database issues are all fatal at this stage. @@ -145,7 +149,7 @@ func (b *bot) migrateDB() { // Adds a constructed handler to the bots handlers list func (b *bot) AddHandler(name string, h Handler) { - b.plugins[strings.ToLower(name)] = h + b.plugins[name] = h b.pluginOrdering = append(b.pluginOrdering, name) if entry := h.RegisterWeb(); entry != nil { b.httpEndPoints[name] = *entry diff --git a/bot/handlers.go b/bot/handlers.go index e28dd65..9df5896 100644 --- a/bot/handlers.go +++ b/bot/handlers.go @@ -23,6 +23,8 @@ func (b *bot) MsgReceived(msg msg.Message) { // msg := b.buildMessage(client, inMsg) // do need to look up user and fix it + log.Println(msg.User.Name) + if strings.HasPrefix(msg.Body, "help ") && msg.Command { parts := strings.Fields(strings.ToLower(msg.Body)) b.checkHelp(msg.Channel, parts) @@ -65,6 +67,10 @@ func (b *bot) React(channel, reaction string, message msg.Message) { b.conn.React(channel, reaction, message) } +func (b *bot) Edit(channel, newMessage, identifier string) { + b.conn.Edit(channel, newMessage, identifier) +} + func (b *bot) GetEmojiList() map[string]string { return b.conn.GetEmojiList() } diff --git a/bot/interfaces.go b/bot/interfaces.go index 23e1185..d476642 100644 --- a/bot/interfaces.go +++ b/bot/interfaces.go @@ -13,11 +13,13 @@ type Bot interface { Config() *config.Config DBVersion() int64 DB() *sqlx.DB + Conn() Connector Who(string) []user.User AddHandler(string, Handler) SendMessage(string, string) SendAction(string, string) React(string, string, msg.Message) + Edit(string, string, string) MsgReceived(msg.Message) EventReceived(msg.Message) Filter(msg.Message, string) string @@ -34,6 +36,7 @@ type Connector interface { SendMessage(channel, message string) SendAction(channel, message string) React(string, string, msg.Message) + Edit(string, string, string) GetEmojiList() map[string]string Serve() error diff --git a/bot/mock.go b/bot/mock.go index 6b809f0..997fe5f 100644 --- a/bot/mock.go +++ b/bot/mock.go @@ -25,6 +25,7 @@ type MockBot struct { func (mb *MockBot) Config() *config.Config { return &mb.Cfg } func (mb *MockBot) DBVersion() int64 { return 1 } func (mb *MockBot) DB() *sqlx.DB { return mb.db } +func (mb *MockBot) Conn() Connector { return nil } func (mb *MockBot) Who(string) []user.User { return []user.User{} } func (mb *MockBot) AddHandler(name string, f Handler) {} func (mb *MockBot) SendMessage(ch string, msg string) { @@ -40,6 +41,7 @@ func (mb *MockBot) LastMessage(ch string) (msg.Message, error) { return msg.Mess func (mb *MockBot) CheckAdmin(nick string) bool { return false } func (mb *MockBot) React(channel, reaction string, message msg.Message) {} +func (mb *MockBot) Edit(channel, newMessage, identifier string) {} func (mb *MockBot) GetEmojiList() map[string]string { return make(map[string]string) } func (mb *MockBot) RegisterFilter(s string, f func(string) string) {} diff --git a/irc/irc.go b/irc/irc.go index 5ff2b07..da2a806 100644 --- a/irc/irc.go +++ b/irc/irc.go @@ -103,6 +103,10 @@ func (i *Irc) React(channel, reaction string, message msg.Message) { //we're not goign to do anything because it's IRC } +func (i *Irc) Edit(channel, newMessage, identifier string) { + //we're not goign to do anything because it's IRC +} + func (i *Irc) GetEmojiList() map[string]string { //we're not goign to do anything because it's IRC return make(map[string]string) diff --git a/main.go b/main.go index f576aca..069a27f 100644 --- a/main.go +++ b/main.go @@ -21,6 +21,7 @@ import ( "github.com/velour/catbase/plugins/leftpad" "github.com/velour/catbase/plugins/reaction" "github.com/velour/catbase/plugins/reminder" + "github.com/velour/catbase/plugins/rpgORdie" "github.com/velour/catbase/plugins/rss" "github.com/velour/catbase/plugins/stats" "github.com/velour/catbase/plugins/talker" @@ -69,6 +70,7 @@ func main() { b.AddHandler("emojifyme", emojifyme.New(b)) b.AddHandler("twitch", twitch.New(b)) b.AddHandler("inventory", inventory.New(b)) + b.AddHandler("rpgORdie", rpgORdie.New(b)) // catches anything left, will always return true b.AddHandler("factoid", fact.New(b)) diff --git a/plugins/rpgORdie/rpgORdie.go b/plugins/rpgORdie/rpgORdie.go new file mode 100644 index 0000000..7201c1b --- /dev/null +++ b/plugins/rpgORdie/rpgORdie.go @@ -0,0 +1,61 @@ +package rpgORdie + +import ( + "strings" + // "log" + "time" + + "github.com/velour/catbase/bot" + "github.com/velour/catbase/bot/msg" + "github.com/velour/catbase/slack" +) + +type RPGPlugin struct { + Bot bot.Bot + Slack *slack.Slack //nasty +} + +func New(b bot.Bot) *RPGPlugin { + return &RPGPlugin{ + Bot: b, + Slack: b.Conn().(*slack.Slack), //oh boy, this is just filthy + } +} + +func (p *RPGPlugin) Message(message msg.Message) bool { + if strings.ToLower(message.Body) == "start rpg" { + p.Bot.SendMessage(message.Channel, "I'll edit this.") + ts := p.Slack.GetLastMessageId() + + time.Sleep(2 * time.Second) + + edited := "" + for i := 0; i <= 5; i++ { + p.Bot.Edit(message.Channel, edited, ts) + edited += ":fire:" + time.Sleep(2 * time.Second) + } + p.Bot.Edit(message.Channel, "HECK YES", ts) + } + return false +} + +func (p *RPGPlugin) LoadData() { + +} + +func (p *RPGPlugin) Help(channel string, parts []string) { + p.Bot.SendMessage(channel, "Go find a walkthrough or something.") +} + +func (p *RPGPlugin) Event(kind string, message msg.Message) bool { + return false +} + +func (p *RPGPlugin) BotMessage(message msg.Message) bool { + return false +} + +func (p *RPGPlugin) RegisterWeb() *string { + return nil +} diff --git a/plugins/rpgORdie/rpgORdie_test.go b/plugins/rpgORdie/rpgORdie_test.go new file mode 100644 index 0000000..42db0f4 --- /dev/null +++ b/plugins/rpgORdie/rpgORdie_test.go @@ -0,0 +1,4 @@ +package rpgORdie + +import ( +) diff --git a/slack/slack.go b/slack/slack.go index 5f885bb..22c5c3a 100644 --- a/slack/slack.go +++ b/slack/slack.go @@ -15,7 +15,7 @@ import ( "regexp" "strconv" "strings" - "sync/atomic" + // "sync/atomic" "time" "github.com/velour/catbase/bot" @@ -38,6 +38,8 @@ type Slack struct { emoji map[string]string + lastMessageId string + eventReceived func(msg.Message) messageReceived func(msg.Message) } @@ -160,6 +162,7 @@ func New(c *config.Config) *Slack { lastRecieved: time.Now(), users: make(map[string]string), emoji: make(map[string]string), + lastMessageId: "", } } @@ -172,17 +175,47 @@ func (s *Slack) RegisterMessageReceived(f func(msg.Message)) { } func (s *Slack) SendMessageType(channel, messageType, subType, message string) error { - m := slackMessage{ - ID: atomic.AddUint64(&idCounter, 1), - Type: messageType, - SubType: subType, - Channel: channel, - Text: message, - } - err := websocket.JSON.Send(s.ws, m) + resp, err := http.PostForm("https://slack.com/api/chat.postMessage", + url.Values{"token": {s.config.Slack.Token}, + "channel": {channel}, + "text": {message}, + }) + if err != nil { - log.Printf("Error sending Slack message: %s", err) + log.Printf("Error sending Slack reaction: %s", err) } + + body, err := ioutil.ReadAll(resp.Body) + resp.Body.Close() + if err != nil { + log.Fatalf("Error reading Slack API body: %s", err) + } + + log.Println(string(body)) + + type MessageResponse struct { + OK bool `json:ok` + Channel string `json:channel` + Timestamp string `json:ts` + } + + var mr MessageResponse + err = json.Unmarshal(body, &mr) + if err != nil { + log.Fatalf("Error parsing message response: %s", err) + } + + bodyAsString := string(body) + + //what the fuck + if strings.Contains(bodyAsString, "\"ts\":\"") { + mr.Timestamp = strings.Split(strings.Split(bodyAsString, "\"ts\":\"")[1], "\"")[0] + } + + s.lastMessageId = mr.Timestamp + + log.Println(mr) + return err } @@ -209,6 +242,46 @@ func (s *Slack) React(channel, reaction string, message msg.Message) { log.Print(resp) } +func (s* Slack) GetLastMessageId() string { + return s.lastMessageId +} + +func (s* Slack) PrintHistory(channel string, howMany int) { + resp, err := http.PostForm("https://slack.com/api/channels.history", + url.Values{"token": {s.config.Slack.Token}, + "channel": {channel}, + "count": {fmt.Sprintf("%d", howMany)}}) + if err != nil { + log.Printf("Error getting slack history: %s", err) + } + body, err := ioutil.ReadAll(resp.Body) + resp.Body.Close() + if err != nil { + log.Fatalf("Error reading Slack API body: %s", err) + } + + log.Println(string(body)) +} + +func (s *Slack) Edit(channel, newMessage, identifier string) { + log.Printf("Editing in (%s) %s: %s", identifier, channel, newMessage) + resp, err := http.PostForm("https://slack.com/api/chat.update", + url.Values{"token": {s.config.Slack.Token}, + "channel": {channel}, + "text": {newMessage}, + "ts": {identifier}}) + if err != nil { + log.Printf("Error sending Slack reaction: %s", err) + } + body, err := ioutil.ReadAll(resp.Body) + resp.Body.Close() + if err != nil { + log.Fatalf("Error reading Slack API body: %s", err) + } + + log.Println(string(body)) +} + func (s *Slack) GetEmojiList() map[string]string { return s.emoji } @@ -275,6 +348,11 @@ func (s *Slack) Serve() error { case "message": if !msg.Hidden { m := s.buildMessage(msg) + + log.Println() + log.Println(m) + log.Println() + if m.Time.Before(s.lastRecieved) { log.Printf("Ignoring message: %+v\nlastRecieved: %v msg: %v", msg.ID, s.lastRecieved, m.Time) } else { From d6c35b94ecf16e8f151a66d391b761dfadb4e810 Mon Sep 17 00:00:00 2001 From: skkiesel Date: Tue, 31 Oct 2017 09:40:03 -0400 Subject: [PATCH 2/8] cleanup! --- bot/bot.go | 4 -- bot/handlers.go | 16 ++--- bot/interfaces.go | 17 +++--- bot/mock.go | 47 ++++++++++++--- irc/irc.go | 12 ++-- plugins/rpgORdie/rpgORdie.go | 10 +--- plugins/rpgORdie/rpgORdie_test.go | 3 +- slack/slack.go | 99 ++++++++++++++----------------- 8 files changed, 113 insertions(+), 95 deletions(-) diff --git a/bot/bot.go b/bot/bot.go index 2507586..eac6f28 100644 --- a/bot/bot.go +++ b/bot/bot.go @@ -110,10 +110,6 @@ func (b *bot) DB() *sqlx.DB { return b.db } -func (b *bot) Conn() Connector { - return b.conn -} - // Create any tables if necessary based on version of DB // Plugins should create their own tables, these are only for official bot stuff // Note: This does not return an error. Database issues are all fatal at this stage. diff --git a/bot/handlers.go b/bot/handlers.go index 9df5896..bb4c340 100644 --- a/bot/handlers.go +++ b/bot/handlers.go @@ -55,20 +55,20 @@ func (b *bot) EventReceived(msg msg.Message) { } } -func (b *bot) SendMessage(channel, message string) { - b.conn.SendMessage(channel, message) +func (b *bot) SendMessage(channel, message string) string { + return b.conn.SendMessage(channel, message) } -func (b *bot) SendAction(channel, message string) { - b.conn.SendAction(channel, message) +func (b *bot) SendAction(channel, message string) string { + return b.conn.SendAction(channel, message) } -func (b *bot) React(channel, reaction string, message msg.Message) { - b.conn.React(channel, reaction, message) +func (b *bot) React(channel, reaction string, message msg.Message) bool { + return b.conn.React(channel, reaction, message) } -func (b *bot) Edit(channel, newMessage, identifier string) { - b.conn.Edit(channel, newMessage, identifier) +func (b *bot) Edit(channel, newMessage, identifier string) bool { + return b.conn.Edit(channel, newMessage, identifier) } func (b *bot) GetEmojiList() map[string]string { diff --git a/bot/interfaces.go b/bot/interfaces.go index d476642..2fc783d 100644 --- a/bot/interfaces.go +++ b/bot/interfaces.go @@ -13,13 +13,12 @@ type Bot interface { Config() *config.Config DBVersion() int64 DB() *sqlx.DB - Conn() Connector Who(string) []user.User AddHandler(string, Handler) - SendMessage(string, string) - SendAction(string, string) - React(string, string, msg.Message) - Edit(string, string, string) + SendMessage(string, string) string + SendAction(string, string) string + React(string, string, msg.Message) bool + Edit(string, string, string) bool MsgReceived(msg.Message) EventReceived(msg.Message) Filter(msg.Message, string) string @@ -33,10 +32,10 @@ type Connector interface { RegisterEventReceived(func(message msg.Message)) RegisterMessageReceived(func(message msg.Message)) - SendMessage(channel, message string) - SendAction(channel, message string) - React(string, string, msg.Message) - Edit(string, string, string) + SendMessage(channel, message string) string + SendAction(channel, message string) string + React(string, string, msg.Message) bool + Edit(string, string, string) bool GetEmojiList() map[string]string Serve() error diff --git a/bot/mock.go b/bot/mock.go index 997fe5f..1e51bb9 100644 --- a/bot/mock.go +++ b/bot/mock.go @@ -3,7 +3,10 @@ package bot import ( + "fmt" "log" + "strconv" + "strings" "github.com/jmoiron/sqlx" "github.com/stretchr/testify/mock" @@ -25,14 +28,16 @@ type MockBot struct { func (mb *MockBot) Config() *config.Config { return &mb.Cfg } func (mb *MockBot) DBVersion() int64 { return 1 } func (mb *MockBot) DB() *sqlx.DB { return mb.db } -func (mb *MockBot) Conn() Connector { return nil } +func (mb *MockBot) Conn() Connector { return nil } func (mb *MockBot) Who(string) []user.User { return []user.User{} } func (mb *MockBot) AddHandler(name string, f Handler) {} -func (mb *MockBot) SendMessage(ch string, msg string) { +func (mb *MockBot) SendMessage(ch string, msg string) string { mb.Messages = append(mb.Messages, msg) + return fmt.Sprintf("m-%d", len(mb.Actions)-1) } -func (mb *MockBot) SendAction(ch string, msg string) { +func (mb *MockBot) SendAction(ch string, msg string) string { mb.Actions = append(mb.Actions, msg) + return fmt.Sprintf("a-%d", len(mb.Actions)-1) } func (mb *MockBot) MsgReceived(msg msg.Message) {} func (mb *MockBot) EventReceived(msg msg.Message) {} @@ -40,10 +45,38 @@ func (mb *MockBot) Filter(msg msg.Message, s string) string { return "" } func (mb *MockBot) LastMessage(ch string) (msg.Message, error) { return msg.Message{}, nil } func (mb *MockBot) CheckAdmin(nick string) bool { return false } -func (mb *MockBot) React(channel, reaction string, message msg.Message) {} -func (mb *MockBot) Edit(channel, newMessage, identifier string) {} -func (mb *MockBot) GetEmojiList() map[string]string { return make(map[string]string) } -func (mb *MockBot) RegisterFilter(s string, f func(string) string) {} +func (mb *MockBot) React(channel, reaction string, message msg.Message) bool { return false } + +func (mb *MockBot) Edit(channel, newMessage, identifier string) bool { + isMessage := identifier[0] == 'm' + if !isMessage && identifier[0] != 'a' { + log.Printf("failed to parse identifier: %s", identifier) + return false + } + + index, err := strconv.Atoi(strings.Split(identifier, "-")[1]) + if err != nil { + log.Printf("failed to parse identifier: %s", identifier) + return false + } + + if isMessage { + if index < len(mb.Messages) { + mb.Messages[index] = newMessage + } else { + return false + } + } else { + if index < len(mb.Actions) { + mb.Actions[index] = newMessage + } else { + return false + } + } + return true +} +func (mb *MockBot) GetEmojiList() map[string]string { return make(map[string]string) } +func (mb *MockBot) RegisterFilter(s string, f func(string) string) {} func NewMockBot() *MockBot { db, err := sqlx.Open("sqlite3_custom", ":memory:") diff --git a/irc/irc.go b/irc/irc.go index da2a806..65de1a7 100644 --- a/irc/irc.go +++ b/irc/irc.go @@ -66,7 +66,7 @@ func (i *Irc) JoinChannel(channel string) { i.Client.Out <- irc.Msg{Cmd: irc.JOIN, Args: []string{channel}} } -func (i *Irc) SendMessage(channel, message string) { +func (i *Irc) SendMessage(channel, message string) string { for len(message) > 0 { m := irc.Msg{ Cmd: "PRIVMSG", @@ -90,21 +90,25 @@ func (i *Irc) SendMessage(channel, message string) { i.Client.Out <- m } + return "NO_IRC_IDENTIFIERS" } // Sends action to channel -func (i *Irc) SendAction(channel, message string) { +func (i *Irc) SendAction(channel, message string) string { message = actionPrefix + " " + message + "\x01" i.SendMessage(channel, message) + return "NO_IRC_IDENTIFIERS" } -func (i *Irc) React(channel, reaction string, message msg.Message) { +func (i *Irc) React(channel, reaction string, message msg.Message) bool { //we're not goign to do anything because it's IRC + return false } -func (i *Irc) Edit(channel, newMessage, identifier string) { +func (i *Irc) Edit(channel, newMessage, identifier string) bool { //we're not goign to do anything because it's IRC + return false } func (i *Irc) GetEmojiList() map[string]string { diff --git a/plugins/rpgORdie/rpgORdie.go b/plugins/rpgORdie/rpgORdie.go index 7201c1b..17418c8 100644 --- a/plugins/rpgORdie/rpgORdie.go +++ b/plugins/rpgORdie/rpgORdie.go @@ -7,25 +7,21 @@ import ( "github.com/velour/catbase/bot" "github.com/velour/catbase/bot/msg" - "github.com/velour/catbase/slack" ) type RPGPlugin struct { - Bot bot.Bot - Slack *slack.Slack //nasty + Bot bot.Bot } func New(b bot.Bot) *RPGPlugin { return &RPGPlugin{ - Bot: b, - Slack: b.Conn().(*slack.Slack), //oh boy, this is just filthy + Bot: b, } } func (p *RPGPlugin) Message(message msg.Message) bool { if strings.ToLower(message.Body) == "start rpg" { - p.Bot.SendMessage(message.Channel, "I'll edit this.") - ts := p.Slack.GetLastMessageId() + ts := p.Bot.SendMessage(message.Channel, "I'll edit this.") time.Sleep(2 * time.Second) diff --git a/plugins/rpgORdie/rpgORdie_test.go b/plugins/rpgORdie/rpgORdie_test.go index 42db0f4..ddcd924 100644 --- a/plugins/rpgORdie/rpgORdie_test.go +++ b/plugins/rpgORdie/rpgORdie_test.go @@ -1,4 +1,3 @@ package rpgORdie -import ( -) +import () diff --git a/slack/slack.go b/slack/slack.go index 22c5c3a..3e7e2ed 100644 --- a/slack/slack.go +++ b/slack/slack.go @@ -38,8 +38,6 @@ type Slack struct { emoji map[string]string - lastMessageId string - eventReceived func(msg.Message) messageReceived func(msg.Message) } @@ -162,10 +160,30 @@ func New(c *config.Config) *Slack { lastRecieved: time.Now(), users: make(map[string]string), emoji: make(map[string]string), - lastMessageId: "", } } +func checkReturnStatus(response *http.Response) bool { + type Response struct { + OK bool `json:"ok"` + } + + body, err := ioutil.ReadAll(response.Body) + response.Body.Close() + if err != nil { + log.Printf("Error reading Slack API body: %s", err) + return false + } + + var resp Response + err = json.Unmarshal(body, &resp) + if err != nil { + log.Printf("Error parsing message response: %s", err) + return false + } + return resp.OK +} + func (s *Slack) RegisterEventReceived(f func(msg.Message)) { s.eventReceived = f } @@ -174,11 +192,11 @@ func (s *Slack) RegisterMessageReceived(f func(msg.Message)) { s.messageReceived = f } -func (s *Slack) SendMessageType(channel, messageType, subType, message string) error { +func (s *Slack) SendMessageType(channel, messageType, subType, message string) (string, error) { resp, err := http.PostForm("https://slack.com/api/chat.postMessage", url.Values{"token": {s.config.Slack.Token}, - "channel": {channel}, - "text": {message}, + "channel": {channel}, + "text": {message}, }) if err != nil { @@ -194,9 +212,9 @@ func (s *Slack) SendMessageType(channel, messageType, subType, message string) e log.Println(string(body)) type MessageResponse struct { - OK bool `json:ok` - Channel string `json:channel` - Timestamp string `json:ts` + OK bool `json:"ok"` + Channel string `json:"channel"` + Timestamp string `json:"ts"` } var mr MessageResponse @@ -212,24 +230,22 @@ func (s *Slack) SendMessageType(channel, messageType, subType, message string) e mr.Timestamp = strings.Split(strings.Split(bodyAsString, "\"ts\":\"")[1], "\"")[0] } - s.lastMessageId = mr.Timestamp - - log.Println(mr) - - return err + return mr.Timestamp, err } -func (s *Slack) SendMessage(channel, message string) { +func (s *Slack) SendMessage(channel, message string) string { log.Printf("Sending message to %s: %s", channel, message) - s.SendMessageType(channel, "message", "", message) + identifier, _ := s.SendMessageType(channel, "message", "", message) + return identifier } -func (s *Slack) SendAction(channel, message string) { +func (s *Slack) SendAction(channel, message string) string { log.Printf("Sending action to %s: %s", channel, message) - s.SendMessageType(channel, "message", "me_message", "_"+message+"_") + identifier, _ := s.SendMessageType(channel, "message", "me_message", "_"+message+"_") + return identifier } -func (s *Slack) React(channel, reaction string, message msg.Message) { +func (s *Slack) React(channel, reaction string, message msg.Message) bool { log.Printf("Reacting in %s: %s", channel, reaction) resp, err := http.PostForm("https://slack.com/api/reactions.add", url.Values{"token": {s.config.Slack.Token}, @@ -237,49 +253,24 @@ func (s *Slack) React(channel, reaction string, message msg.Message) { "channel": {channel}, "timestamp": {message.AdditionalData["RAW_SLACK_TIMESTAMP"]}}) if err != nil { - log.Printf("Error sending Slack reaction: %s", err) + log.Println("reaction failed: %s", err) + return false } - log.Print(resp) + return checkReturnStatus(resp) } -func (s* Slack) GetLastMessageId() string { - return s.lastMessageId -} - -func (s* Slack) PrintHistory(channel string, howMany int) { - resp, err := http.PostForm("https://slack.com/api/channels.history", - url.Values{"token": {s.config.Slack.Token}, - "channel": {channel}, - "count": {fmt.Sprintf("%d", howMany)}}) - if err != nil { - log.Printf("Error getting slack history: %s", err) - } - body, err := ioutil.ReadAll(resp.Body) - resp.Body.Close() - if err != nil { - log.Fatalf("Error reading Slack API body: %s", err) - } - - log.Println(string(body)) -} - -func (s *Slack) Edit(channel, newMessage, identifier string) { +func (s *Slack) Edit(channel, newMessage, identifier string) bool { log.Printf("Editing in (%s) %s: %s", identifier, channel, newMessage) resp, err := http.PostForm("https://slack.com/api/chat.update", url.Values{"token": {s.config.Slack.Token}, - "channel": {channel}, - "text": {newMessage}, - "ts": {identifier}}) + "channel": {channel}, + "text": {newMessage}, + "ts": {identifier}}) if err != nil { - log.Printf("Error sending Slack reaction: %s", err) + log.Println("edit failed: %s", err) + return false } - body, err := ioutil.ReadAll(resp.Body) - resp.Body.Close() - if err != nil { - log.Fatalf("Error reading Slack API body: %s", err) - } - - log.Println(string(body)) + return checkReturnStatus(resp) } func (s *Slack) GetEmojiList() map[string]string { From 42b1356eb20d772729fec42191e1eec621088ce9 Mon Sep 17 00:00:00 2001 From: skkiesel Date: Tue, 31 Oct 2017 09:48:35 -0400 Subject: [PATCH 3/8] remove some unneccessary code when parsing sent message response --- slack/slack.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/slack/slack.go b/slack/slack.go index 3e7e2ed..9808e2c 100644 --- a/slack/slack.go +++ b/slack/slack.go @@ -223,13 +223,6 @@ func (s *Slack) SendMessageType(channel, messageType, subType, message string) ( log.Fatalf("Error parsing message response: %s", err) } - bodyAsString := string(body) - - //what the fuck - if strings.Contains(bodyAsString, "\"ts\":\"") { - mr.Timestamp = strings.Split(strings.Split(bodyAsString, "\"ts\":\"")[1], "\"")[0] - } - return mr.Timestamp, err } From 3009a646e60fb042877c12285f636640f1cc05f5 Mon Sep 17 00:00:00 2001 From: skkiesel Date: Tue, 31 Oct 2017 10:07:20 -0400 Subject: [PATCH 4/8] support replies --- bot/handlers.go | 4 +++ bot/interfaces.go | 2 ++ bot/mock.go | 1 + irc/irc.go | 4 +++ plugins/rpgORdie/rpgORdie.go | 2 ++ slack/slack.go | 62 ++++++++++++++++++++++++++++++++---- 6 files changed, 69 insertions(+), 6 deletions(-) diff --git a/bot/handlers.go b/bot/handlers.go index bb4c340..81e9154 100644 --- a/bot/handlers.go +++ b/bot/handlers.go @@ -63,6 +63,10 @@ func (b *bot) SendAction(channel, message string) string { return b.conn.SendAction(channel, message) } +func (b *bot) ReplyToMessage(channel, message, identifier string) (string, bool) { + return b.conn.ReplyToMessage(channel, message, identifier) +} + func (b *bot) React(channel, reaction string, message msg.Message) bool { return b.conn.React(channel, reaction, message) } diff --git a/bot/interfaces.go b/bot/interfaces.go index 2fc783d..d1e374a 100644 --- a/bot/interfaces.go +++ b/bot/interfaces.go @@ -17,6 +17,7 @@ type Bot interface { AddHandler(string, Handler) SendMessage(string, string) string SendAction(string, string) string + ReplyToMessage(channel, message, identifier string) (string, bool) React(string, string, msg.Message) bool Edit(string, string, string) bool MsgReceived(msg.Message) @@ -34,6 +35,7 @@ type Connector interface { SendMessage(channel, message string) string SendAction(channel, message string) string + ReplyToMessage(channel, message, identifier string) (string, bool) React(string, string, msg.Message) bool Edit(string, string, string) bool GetEmojiList() map[string]string diff --git a/bot/mock.go b/bot/mock.go index 1e51bb9..fdb5178 100644 --- a/bot/mock.go +++ b/bot/mock.go @@ -39,6 +39,7 @@ func (mb *MockBot) SendAction(ch string, msg string) string { mb.Actions = append(mb.Actions, msg) return fmt.Sprintf("a-%d", len(mb.Actions)-1) } +func (mb *MockBot) ReplyToMessage(channel, message, identifier string) (string, bool) { return "", false } func (mb *MockBot) MsgReceived(msg msg.Message) {} func (mb *MockBot) EventReceived(msg msg.Message) {} func (mb *MockBot) Filter(msg msg.Message, s string) string { return "" } diff --git a/irc/irc.go b/irc/irc.go index 65de1a7..4d7b3bf 100644 --- a/irc/irc.go +++ b/irc/irc.go @@ -101,6 +101,10 @@ func (i *Irc) SendAction(channel, message string) string { return "NO_IRC_IDENTIFIERS" } +func (i *Irc) ReplyToMessage(channel, message, identifier string) (string, bool) { + return "NO_IRC_IDENTIFIERS", false +} + func (i *Irc) React(channel, reaction string, message msg.Message) bool { //we're not goign to do anything because it's IRC return false diff --git a/plugins/rpgORdie/rpgORdie.go b/plugins/rpgORdie/rpgORdie.go index 17418c8..5c5b619 100644 --- a/plugins/rpgORdie/rpgORdie.go +++ b/plugins/rpgORdie/rpgORdie.go @@ -32,6 +32,8 @@ func (p *RPGPlugin) Message(message msg.Message) bool { time.Sleep(2 * time.Second) } p.Bot.Edit(message.Channel, "HECK YES", ts) + + p.Bot.ReplyToMessage(message.Channel, "How's this reply?", ts) } return false } diff --git a/slack/slack.go b/slack/slack.go index 9808e2c..29e5ef9 100644 --- a/slack/slack.go +++ b/slack/slack.go @@ -5,6 +5,7 @@ package slack import ( "encoding/json" + "errors" "fmt" "html" "io" @@ -192,15 +193,20 @@ func (s *Slack) RegisterMessageReceived(f func(msg.Message)) { s.messageReceived = f } -func (s *Slack) SendMessageType(channel, messageType, subType, message string) (string, error) { - resp, err := http.PostForm("https://slack.com/api/chat.postMessage", +func (s *Slack) SendMessageType(channel, message string, meMessage bool) (string, error) { + postUrl := "https://slack.com/api/chat.postMessage" + if meMessage { + postUrl = "https://slack.com/api/chat.meMessage" + } + + resp, err := http.PostForm(postUrl, url.Values{"token": {s.config.Slack.Token}, "channel": {channel}, "text": {message}, }) if err != nil { - log.Printf("Error sending Slack reaction: %s", err) + log.Printf("Error sending Slack message: %s", err) } body, err := ioutil.ReadAll(resp.Body) @@ -213,7 +219,6 @@ func (s *Slack) SendMessageType(channel, messageType, subType, message string) ( type MessageResponse struct { OK bool `json:"ok"` - Channel string `json:"channel"` Timestamp string `json:"ts"` } @@ -223,21 +228,66 @@ func (s *Slack) SendMessageType(channel, messageType, subType, message string) ( log.Fatalf("Error parsing message response: %s", err) } + if !mr.OK { + return "", errors.New("failure response received") + } + return mr.Timestamp, err } func (s *Slack) SendMessage(channel, message string) string { log.Printf("Sending message to %s: %s", channel, message) - identifier, _ := s.SendMessageType(channel, "message", "", message) + identifier, _ := s.SendMessageType(channel, message, false) return identifier } func (s *Slack) SendAction(channel, message string) string { log.Printf("Sending action to %s: %s", channel, message) - identifier, _ := s.SendMessageType(channel, "message", "me_message", "_"+message+"_") + identifier, _ := s.SendMessageType(channel, "_"+message+"_", true) return identifier } +func (s *Slack) ReplyToMessage(channel, message, identifier string) (string, bool) { + resp, err := http.PostForm("https://slack.com/api/chat.postMessage", + url.Values{"token": {s.config.Slack.Token}, + "channel": {channel}, + "text": {message}, + "thread_ts": {identifier}, + }) + + if err != nil { + log.Printf("Error sending Slack reply: %s", err) + return "", false + } + + body, err := ioutil.ReadAll(resp.Body) + resp.Body.Close() + if err != nil { + log.Printf("Error reading Slack API body: %s", err) + return "", false + } + + log.Println(string(body)) + + type MessageResponse struct { + OK bool `json:"ok"` + Timestamp string `json:"ts"` + } + + var mr MessageResponse + err = json.Unmarshal(body, &mr) + if err != nil { + log.Printf("Error parsing message response: %s", err) + return "", false + } + + if !mr.OK { + return "", false + } + + return mr.Timestamp, err == nil +} + func (s *Slack) React(channel, reaction string, message msg.Message) bool { log.Printf("Reacting in %s: %s", channel, reaction) resp, err := http.PostForm("https://slack.com/api/reactions.add", From d9bb7ec3c0aead5e4852e90870e38b6090cbcdae Mon Sep 17 00:00:00 2001 From: skkiesel Date: Tue, 31 Oct 2017 10:16:41 -0400 Subject: [PATCH 5/8] sometimes you have an id, sometimes a message, we should support relpying to both --- bot/handlers.go | 8 ++++++-- bot/interfaces.go | 6 ++++-- bot/mock.go | 3 ++- irc/irc.go | 6 +++++- plugins/rpgORdie/rpgORdie.go | 2 +- slack/slack.go | 6 +++++- 6 files changed, 23 insertions(+), 8 deletions(-) diff --git a/bot/handlers.go b/bot/handlers.go index 81e9154..234e85e 100644 --- a/bot/handlers.go +++ b/bot/handlers.go @@ -63,8 +63,12 @@ func (b *bot) SendAction(channel, message string) string { return b.conn.SendAction(channel, message) } -func (b *bot) ReplyToMessage(channel, message, identifier string) (string, bool) { - return b.conn.ReplyToMessage(channel, message, identifier) +func (b *bot) ReplyToMessageIdentifier(channel, message, identifier string) (string, bool) { + return b.conn.ReplyToMessageIdentifier(channel, message, identifier) +} + +func (b *bot) ReplyToMessage(channel, message string, replyTo msg.Message) (string, bool) { + return b.conn.ReplyToMessage(channel, message, replyTo) } func (b *bot) React(channel, reaction string, message msg.Message) bool { diff --git a/bot/interfaces.go b/bot/interfaces.go index d1e374a..2e76e93 100644 --- a/bot/interfaces.go +++ b/bot/interfaces.go @@ -17,7 +17,8 @@ type Bot interface { AddHandler(string, Handler) SendMessage(string, string) string SendAction(string, string) string - ReplyToMessage(channel, message, identifier string) (string, bool) + ReplyToMessageIdentifier(string, string, string) (string, bool) + ReplyToMessage(string, string, msg.Message) (string, bool) React(string, string, msg.Message) bool Edit(string, string, string) bool MsgReceived(msg.Message) @@ -35,7 +36,8 @@ type Connector interface { SendMessage(channel, message string) string SendAction(channel, message string) string - ReplyToMessage(channel, message, identifier string) (string, bool) + ReplyToMessageIdentifier(string, string, string) (string, bool) + ReplyToMessage(string, string, msg.Message) (string, bool) React(string, string, msg.Message) bool Edit(string, string, string) bool GetEmojiList() map[string]string diff --git a/bot/mock.go b/bot/mock.go index fdb5178..1286e3f 100644 --- a/bot/mock.go +++ b/bot/mock.go @@ -39,7 +39,8 @@ func (mb *MockBot) SendAction(ch string, msg string) string { mb.Actions = append(mb.Actions, msg) return fmt.Sprintf("a-%d", len(mb.Actions)-1) } -func (mb *MockBot) ReplyToMessage(channel, message, identifier string) (string, bool) { return "", false } +func (mb *MockBot) ReplyToMessageIdentifier(channel, message, identifier string) (string, bool) { return "", false } +func (mb *MockBot) ReplyToMessage(channel, message string, replyTo msg.Message) (string, bool) { return "", false } func (mb *MockBot) MsgReceived(msg msg.Message) {} func (mb *MockBot) EventReceived(msg msg.Message) {} func (mb *MockBot) Filter(msg msg.Message, s string) string { return "" } diff --git a/irc/irc.go b/irc/irc.go index 4d7b3bf..d348610 100644 --- a/irc/irc.go +++ b/irc/irc.go @@ -101,7 +101,11 @@ func (i *Irc) SendAction(channel, message string) string { return "NO_IRC_IDENTIFIERS" } -func (i *Irc) ReplyToMessage(channel, message, identifier string) (string, bool) { +func (i *Irc) ReplyToMessageIdentifier(channel, message, identifier string) (string, bool) { + return "NO_IRC_IDENTIFIERS", false +} + +func (i *Irc) ReplyToMessage(channel, message string, replyTo msg.Message) (string, bool) { return "NO_IRC_IDENTIFIERS", false } diff --git a/plugins/rpgORdie/rpgORdie.go b/plugins/rpgORdie/rpgORdie.go index 5c5b619..2733d7b 100644 --- a/plugins/rpgORdie/rpgORdie.go +++ b/plugins/rpgORdie/rpgORdie.go @@ -33,7 +33,7 @@ func (p *RPGPlugin) Message(message msg.Message) bool { } p.Bot.Edit(message.Channel, "HECK YES", ts) - p.Bot.ReplyToMessage(message.Channel, "How's this reply?", ts) + p.Bot.ReplyToMessageIdentifier(message.Channel, "How's this reply?", ts) } return false } diff --git a/slack/slack.go b/slack/slack.go index 29e5ef9..b00ed3e 100644 --- a/slack/slack.go +++ b/slack/slack.go @@ -247,7 +247,7 @@ func (s *Slack) SendAction(channel, message string) string { return identifier } -func (s *Slack) ReplyToMessage(channel, message, identifier string) (string, bool) { +func (s *Slack) ReplyToMessageIdentifier(channel, message, identifier string) (string, bool) { resp, err := http.PostForm("https://slack.com/api/chat.postMessage", url.Values{"token": {s.config.Slack.Token}, "channel": {channel}, @@ -288,6 +288,10 @@ func (s *Slack) ReplyToMessage(channel, message, identifier string) (string, boo return mr.Timestamp, err == nil } +func (s *Slack) ReplyToMessage(channel, message string, replyTo msg.Message) (string, bool) { + return s.ReplyToMessageIdentifier(channel, message, replyTo.AdditionalData["RAW_SLACK_TIMESTAMP"]) +} + func (s *Slack) React(channel, reaction string, message msg.Message) bool { log.Printf("Reacting in %s: %s", channel, reaction) resp, err := http.PostForm("https://slack.com/api/reactions.add", From 54b83cd44433df483732a961ca11dbf93cf26cc9 Mon Sep 17 00:00:00 2001 From: skkiesel Date: Tue, 31 Oct 2017 14:14:45 -0400 Subject: [PATCH 6/8] listening to thread responses to rpg threads only --- bot/bot.go | 1 + bot/handlers.go | 15 ++++++++-- bot/interfaces.go | 3 ++ irc/irc.go | 5 ++++ plugins/admin/admin.go | 2 ++ plugins/babbler/babbler.go | 2 ++ plugins/beers/beers.go | 2 ++ plugins/counter/counter.go | 2 ++ plugins/dice/dice.go | 2 ++ plugins/downtime/downtime.go | 2 ++ plugins/emojifyme/emojifyme.go | 2 ++ plugins/fact/factoid.go | 2 ++ plugins/fact/remember.go | 2 ++ plugins/first/first.go | 2 ++ plugins/inventory/inventory.go | 2 ++ plugins/leftpad/leftpad.go | 2 ++ plugins/reaction/reaction.go | 2 ++ plugins/reminder/reminder.go | 2 ++ plugins/rpgORdie/rpgORdie.go | 18 ++++++++++-- plugins/rss/rss.go | 2 ++ plugins/stats/stats.go | 2 ++ plugins/talker/talker.go | 2 ++ plugins/twitch/twitch.go | 2 ++ plugins/your/your.go | 2 ++ plugins/zork/zork.go | 2 ++ slack/slack.go | 52 +++++++++++++++++++++++++++++----- 26 files changed, 122 insertions(+), 12 deletions(-) diff --git a/bot/bot.go b/bot/bot.go index eac6f28..777229c 100644 --- a/bot/bot.go +++ b/bot/bot.go @@ -93,6 +93,7 @@ func New(config *config.Config, connector Connector) Bot { connector.RegisterMessageReceived(bot.MsgReceived) connector.RegisterEventReceived(bot.EventReceived) + connector.RegisterReplyMessageReceived(bot.ReplyMsgReceived) return bot } diff --git a/bot/handlers.go b/bot/handlers.go index 234e85e..651e0ae 100644 --- a/bot/handlers.go +++ b/bot/handlers.go @@ -22,9 +22,6 @@ func (b *bot) MsgReceived(msg msg.Message) { // msg := b.buildMessage(client, inMsg) // do need to look up user and fix it - - log.Println(msg.User.Name) - if strings.HasPrefix(msg.Body, "help ") && msg.Command { parts := strings.Fields(strings.ToLower(msg.Body)) b.checkHelp(msg.Channel, parts) @@ -55,6 +52,18 @@ func (b *bot) EventReceived(msg msg.Message) { } } +// Handle incoming replys +func (b *bot) ReplyMsgReceived(msg msg.Message, identifier string) { + log.Println("Received message: ", msg) + + for _, name := range b.pluginOrdering { + p := b.plugins[name] + if p.ReplyMessage(msg, identifier) { + break + } + } +} + func (b *bot) SendMessage(channel, message string) string { return b.conn.SendMessage(channel, message) } diff --git a/bot/interfaces.go b/bot/interfaces.go index 2e76e93..2780d29 100644 --- a/bot/interfaces.go +++ b/bot/interfaces.go @@ -22,6 +22,7 @@ type Bot interface { React(string, string, msg.Message) bool Edit(string, string, string) bool MsgReceived(msg.Message) + ReplyMsgReceived(msg.Message, string) EventReceived(msg.Message) Filter(msg.Message, string) string LastMessage(string) (msg.Message, error) @@ -33,6 +34,7 @@ type Bot interface { type Connector interface { RegisterEventReceived(func(message msg.Message)) RegisterMessageReceived(func(message msg.Message)) + RegisterReplyMessageReceived(func(msg.Message, string)) SendMessage(channel, message string) string SendAction(channel, message string) string @@ -50,6 +52,7 @@ type Connector interface { type Handler interface { Message(message msg.Message) bool Event(kind string, message msg.Message) bool + ReplyMessage(msg.Message, string) bool BotMessage(message msg.Message) bool Help(channel string, parts []string) RegisterWeb() *string diff --git a/irc/irc.go b/irc/irc.go index d348610..4c34529 100644 --- a/irc/irc.go +++ b/irc/irc.go @@ -44,6 +44,7 @@ type Irc struct { eventReceived func(msg.Message) messageReceived func(msg.Message) + replyMessageReceived func(msg.Message, string) } func New(c *config.Config) *Irc { @@ -61,6 +62,10 @@ func (i *Irc) RegisterMessageReceived(f func(msg.Message)) { i.messageReceived = f } +func (i *Irc) RegisterReplyMessageReceived(f func(msg.Message, string)) { + i.replyMessageReceived = f +} + func (i *Irc) JoinChannel(channel string) { log.Printf("Joining channel: %s", channel) i.Client.Out <- irc.Msg{Cmd: irc.JOIN, Args: []string{channel}} diff --git a/plugins/admin/admin.go b/plugins/admin/admin.go index 85988dc..1113bdd 100644 --- a/plugins/admin/admin.go +++ b/plugins/admin/admin.go @@ -117,3 +117,5 @@ func (p *AdminPlugin) BotMessage(message msg.Message) bool { func (p *AdminPlugin) RegisterWeb() *string { return nil } + +func (p *AdminPlugin) ReplyMessage(message msg.Message, identifier string) bool { return false } diff --git a/plugins/babbler/babbler.go b/plugins/babbler/babbler.go index e5961c9..0ae0b58 100644 --- a/plugins/babbler/babbler.go +++ b/plugins/babbler/babbler.go @@ -935,3 +935,5 @@ func (p *BabblerPlugin) babbleSeedBookends(babblerName string, start, end []stri return strings.Join(words, " "), nil } + +func (p *BabblerPlugin) ReplyMessage(message msg.Message, identifier string) bool { return false } diff --git a/plugins/beers/beers.go b/plugins/beers/beers.go index 1bc6521..6d1b83e 100644 --- a/plugins/beers/beers.go +++ b/plugins/beers/beers.go @@ -461,3 +461,5 @@ func (p *BeersPlugin) BotMessage(message msg.Message) bool { func (p *BeersPlugin) RegisterWeb() *string { return nil } + +func (p *BeersPlugin) ReplyMessage(message msg.Message, identifier string) bool { return false } diff --git a/plugins/counter/counter.go b/plugins/counter/counter.go index ebe51b0..ed70349 100644 --- a/plugins/counter/counter.go +++ b/plugins/counter/counter.go @@ -364,3 +364,5 @@ func (p *CounterPlugin) BotMessage(message msg.Message) bool { func (p *CounterPlugin) RegisterWeb() *string { return nil } + +func (p *CounterPlugin) ReplyMessage(message msg.Message, identifier string) bool { return false } diff --git a/plugins/dice/dice.go b/plugins/dice/dice.go index 07484ce..3ee6dc3 100644 --- a/plugins/dice/dice.go +++ b/plugins/dice/dice.go @@ -100,3 +100,5 @@ func (p *DicePlugin) BotMessage(message msg.Message) bool { func (p *DicePlugin) RegisterWeb() *string { return nil } + +func (p *DicePlugin) ReplyMessage(message msg.Message, identifier string) bool { return false } diff --git a/plugins/downtime/downtime.go b/plugins/downtime/downtime.go index e553ed2..ef9df9e 100644 --- a/plugins/downtime/downtime.go +++ b/plugins/downtime/downtime.go @@ -231,3 +231,5 @@ func (p *DowntimePlugin) BotMessage(message msg.Message) bool { func (p *DowntimePlugin) RegisterWeb() *string { return nil } + +func (p *DowntimePlugin) ReplyMessage(message msg.Message, identifier string) bool { return false } diff --git a/plugins/emojifyme/emojifyme.go b/plugins/emojifyme/emojifyme.go index 65b892f..e8a6119 100644 --- a/plugins/emojifyme/emojifyme.go +++ b/plugins/emojifyme/emojifyme.go @@ -112,3 +112,5 @@ func (p *EmojifyMePlugin) BotMessage(message msg.Message) bool { func (p *EmojifyMePlugin) RegisterWeb() *string { return nil } + +func (p *EmojifyMePlugin) ReplyMessage(message msg.Message, identifier string) bool { return false } diff --git a/plugins/fact/factoid.go b/plugins/fact/factoid.go index be364cf..17a4e4a 100644 --- a/plugins/fact/factoid.go +++ b/plugins/fact/factoid.go @@ -764,3 +764,5 @@ func (p *Factoid) serveQuery(w http.ResponseWriter, r *http.Request) { log.Println(err) } } + +func (p *Factoid) ReplyMessage(message msg.Message, identifier string) bool { return false } diff --git a/plugins/fact/remember.go b/plugins/fact/remember.go index e4fc6bd..1038eb7 100644 --- a/plugins/fact/remember.go +++ b/plugins/fact/remember.go @@ -170,3 +170,5 @@ func (p *RememberPlugin) recordMsg(message msg.Message) { log.Printf("Logging message: %s: %s", message.User.Name, message.Body) p.Log[message.Channel] = append(p.Log[message.Channel], message) } + +func (p *RememberPlugin) ReplyMessage(message msg.Message, identifier string) bool { return false } diff --git a/plugins/first/first.go b/plugins/first/first.go index 9d63c6f..3614576 100644 --- a/plugins/first/first.go +++ b/plugins/first/first.go @@ -228,3 +228,5 @@ func (p *FirstPlugin) BotMessage(message msg.Message) bool { func (p *FirstPlugin) RegisterWeb() *string { return nil } + +func (p *FirstPlugin) ReplyMessage(message msg.Message, identifier string) bool { return false } diff --git a/plugins/inventory/inventory.go b/plugins/inventory/inventory.go index abbaa35..7efb807 100644 --- a/plugins/inventory/inventory.go +++ b/plugins/inventory/inventory.go @@ -236,3 +236,5 @@ func (p *InventoryPlugin) RegisterWeb() *string { // nothing to register return nil } + +func (p *InventoryPlugin) ReplyMessage(message msg.Message, identifier string) bool { return false } diff --git a/plugins/leftpad/leftpad.go b/plugins/leftpad/leftpad.go index 6beb410..11098d9 100644 --- a/plugins/leftpad/leftpad.go +++ b/plugins/leftpad/leftpad.go @@ -76,3 +76,5 @@ func (p *LeftpadPlugin) RegisterWeb() *string { // nothing to register return nil } + +func (p *LeftpadPlugin) ReplyMessage(message msg.Message, identifier string) bool { return false } diff --git a/plugins/reaction/reaction.go b/plugins/reaction/reaction.go index a52c17f..7b204b4 100644 --- a/plugins/reaction/reaction.go +++ b/plugins/reaction/reaction.go @@ -80,3 +80,5 @@ func (p *ReactionPlugin) BotMessage(message msg.Message) bool { func (p *ReactionPlugin) RegisterWeb() *string { return nil } + +func (p *ReactionPlugin) ReplyMessage(message msg.Message, identifier string) bool { return false } diff --git a/plugins/reminder/reminder.go b/plugins/reminder/reminder.go index 1699da2..f55cb3d 100644 --- a/plugins/reminder/reminder.go +++ b/plugins/reminder/reminder.go @@ -322,3 +322,5 @@ func reminderer(p *ReminderPlugin) { p.queueUpNextReminder() } } + +func (p *ReminderPlugin) ReplyMessage(message msg.Message, identifier string) bool { return false } diff --git a/plugins/rpgORdie/rpgORdie.go b/plugins/rpgORdie/rpgORdie.go index 2733d7b..d922f55 100644 --- a/plugins/rpgORdie/rpgORdie.go +++ b/plugins/rpgORdie/rpgORdie.go @@ -2,7 +2,6 @@ package rpgORdie import ( "strings" - // "log" "time" "github.com/velour/catbase/bot" @@ -11,11 +10,13 @@ import ( type RPGPlugin struct { Bot bot.Bot + listenFor map[string]bool } func New(b bot.Bot) *RPGPlugin { return &RPGPlugin{ Bot: b, + listenFor: map[string]bool{}, } } @@ -23,17 +24,20 @@ func (p *RPGPlugin) Message(message msg.Message) bool { if strings.ToLower(message.Body) == "start rpg" { ts := p.Bot.SendMessage(message.Channel, "I'll edit this.") + p.listenFor[ts] = true + time.Sleep(2 * time.Second) edited := "" for i := 0; i <= 5; i++ { p.Bot.Edit(message.Channel, edited, ts) edited += ":fire:" - time.Sleep(2 * time.Second) + time.Sleep(500 * time.Millisecond) } p.Bot.Edit(message.Channel, "HECK YES", ts) p.Bot.ReplyToMessageIdentifier(message.Channel, "How's this reply?", ts) + return true } return false } @@ -57,3 +61,13 @@ func (p *RPGPlugin) BotMessage(message msg.Message) bool { func (p *RPGPlugin) RegisterWeb() *string { return nil } + +func (p *RPGPlugin) ReplyMessage(message msg.Message, identifier string) bool { + if strings.ToLower(message.User.Name) != strings.ToLower(p.Bot.Config().Nick) { + if _, ok := p.listenFor[identifier]; ok { + p.Bot.ReplyToMessageIdentifier(message.Channel, "Pong", identifier) + return true + } + } + return false +} diff --git a/plugins/rss/rss.go b/plugins/rss/rss.go index bc7bee5..099cdf9 100644 --- a/plugins/rss/rss.go +++ b/plugins/rss/rss.go @@ -117,3 +117,5 @@ func (p *RSSPlugin) BotMessage(message msg.Message) bool { func (p *RSSPlugin) RegisterWeb() *string { return nil } + +func (p *RSSPlugin) ReplyMessage(message msg.Message, identifier string) bool { return false } diff --git a/plugins/stats/stats.go b/plugins/stats/stats.go index 7b7039b..81450b2 100644 --- a/plugins/stats/stats.go +++ b/plugins/stats/stats.go @@ -275,3 +275,5 @@ func (p *StatsPlugin) mkSightingStat(message msg.Message) stats { func (p *StatsPlugin) mkChannelStat(message msg.Message) stats { return stats{stat{mkDay(), "channel", message.Channel, 1}} } + +func (p *StatsPlugin) ReplyMessage(message msg.Message, identifier string) bool { return false } diff --git a/plugins/talker/talker.go b/plugins/talker/talker.go index 1e01b90..17e9d1b 100644 --- a/plugins/talker/talker.go +++ b/plugins/talker/talker.go @@ -119,3 +119,5 @@ func (p *TalkerPlugin) BotMessage(message msg.Message) bool { func (p *TalkerPlugin) RegisterWeb() *string { return nil } + +func (p *TalkerPlugin) ReplyMessage(message msg.Message, identifier string) bool { return false } diff --git a/plugins/twitch/twitch.go b/plugins/twitch/twitch.go index 4a5c1a0..941b55a 100644 --- a/plugins/twitch/twitch.go +++ b/plugins/twitch/twitch.go @@ -238,3 +238,5 @@ func (p *TwitchPlugin) checkTwitch(channel string, twitcher *Twitcher, alwaysPri twitcher.game = game } } + +func (p *TwitchPlugin) ReplyMessage(message msg.Message, identifier string) bool { return false } diff --git a/plugins/your/your.go b/plugins/your/your.go index 9100d37..9e24082 100644 --- a/plugins/your/your.go +++ b/plugins/your/your.go @@ -66,3 +66,5 @@ func (p *YourPlugin) BotMessage(message msg.Message) bool { func (p *YourPlugin) RegisterWeb() *string { return nil } + +func (p *YourPlugin) ReplyMessage(message msg.Message, identifier string) bool { return false } diff --git a/plugins/zork/zork.go b/plugins/zork/zork.go index 7bd97bd..cabc6d2 100644 --- a/plugins/zork/zork.go +++ b/plugins/zork/zork.go @@ -122,3 +122,5 @@ func (p *ZorkPlugin) Help(ch string, _ []string) { } func (p *ZorkPlugin) RegisterWeb() *string { return nil } + +func (p *ZorkPlugin) ReplyMessage(message msg.Message, identifier string) bool { return false } diff --git a/slack/slack.go b/slack/slack.go index b00ed3e..b22f622 100644 --- a/slack/slack.go +++ b/slack/slack.go @@ -41,6 +41,7 @@ type Slack struct { eventReceived func(msg.Message) messageReceived func(msg.Message) + replyMessageReceived func(msg.Message, string) } var idCounter uint64 @@ -134,6 +135,7 @@ type slackMessage struct { User string `json:"user"` Username string `json:"username"` Ts string `json:"ts"` + ThreadTs string `json:"thread_ts"` Error struct { Code uint64 `json:"code"` Msg string `json:"msg"` @@ -193,6 +195,10 @@ func (s *Slack) RegisterMessageReceived(f func(msg.Message)) { s.messageReceived = f } +func (s *Slack) RegisterReplyMessageReceived(f func(msg.Message, string)) { + s.replyMessageReceived = f +} + func (s *Slack) SendMessageType(channel, message string, meMessage bool) (string, error) { postUrl := "https://slack.com/api/chat.postMessage" if meMessage { @@ -384,19 +390,17 @@ func (s *Slack) Serve() error { } switch msg.Type { case "message": - if !msg.Hidden { + if !msg.Hidden && msg.ThreadTs == "" { m := s.buildMessage(msg) - - log.Println() - log.Println(m) - log.Println() - if m.Time.Before(s.lastRecieved) { log.Printf("Ignoring message: %+v\nlastRecieved: %v msg: %v", msg.ID, s.lastRecieved, m.Time) } else { s.lastRecieved = m.Time - s.messageReceived(s.buildMessage(msg)) + s.messageReceived(m) } + } else if msg.ThreadTs != "" { + //we're throwing away some information here by not parsing the correct reply object type, but that's okay + s.replyMessageReceived(s.buildLightReplyMessage(msg), msg.ThreadTs) } else { log.Printf("THAT MESSAGE WAS HIDDEN: %+v", msg.ID) } @@ -453,6 +457,40 @@ func (s *Slack) buildMessage(m slackMessage) msg.Message { } } +func (s *Slack) buildLightReplyMessage(m slackMessage) msg.Message { + text := html.UnescapeString(m.Text) + + text = fixText(s.getUser, text) + + isCmd, text := bot.IsCmd(s.config, text) + + isAction := m.SubType == "me_message" + + u, _ := s.getUser(m.User) + if m.Username != "" { + u = m.Username + } + + tstamp := slackTStoTime(m.Ts) + + return msg.Message{ + User: &user.User{ + ID: m.User, + Name: u, + }, + Body: text, + Raw: m.Text, + Channel: m.Channel, + Command: isCmd, + Action: isAction, + Host: string(m.ID), + Time: tstamp, + AdditionalData: map[string]string{ + "RAW_SLACK_TIMESTAMP": m.Ts, + }, + } +} + // markAllChannelsRead gets a list of all channels and marks each as read func (s *Slack) markAllChannelsRead() { chs := s.getAllChannels() From 1ac566c2c2345a9ddc029de87e34e80a11794aac Mon Sep 17 00:00:00 2001 From: skkiesel Date: Thu, 2 Nov 2017 16:32:02 -0400 Subject: [PATCH 7/8] sokobass. --- bot/mock.go | 13 +++- plugins/rpgORdie/rpgORdie.go | 140 +++++++++++++++++++++++++++++------ 2 files changed, 129 insertions(+), 24 deletions(-) diff --git a/bot/mock.go b/bot/mock.go index 1286e3f..7d6c6e6 100644 --- a/bot/mock.go +++ b/bot/mock.go @@ -39,8 +39,12 @@ func (mb *MockBot) SendAction(ch string, msg string) string { mb.Actions = append(mb.Actions, msg) return fmt.Sprintf("a-%d", len(mb.Actions)-1) } -func (mb *MockBot) ReplyToMessageIdentifier(channel, message, identifier string) (string, bool) { return "", false } -func (mb *MockBot) ReplyToMessage(channel, message string, replyTo msg.Message) (string, bool) { return "", false } +func (mb *MockBot) ReplyToMessageIdentifier(channel, message, identifier string) (string, bool) { + return "", false +} +func (mb *MockBot) ReplyToMessage(channel, message string, replyTo msg.Message) (string, bool) { + return "", false +} func (mb *MockBot) MsgReceived(msg msg.Message) {} func (mb *MockBot) EventReceived(msg msg.Message) {} func (mb *MockBot) Filter(msg msg.Message, s string) string { return "" } @@ -77,6 +81,11 @@ func (mb *MockBot) Edit(channel, newMessage, identifier string) bool { } return true } + +func (mb *MockBot) ReplyMsgReceived(msg.Message, string) { + +} + func (mb *MockBot) GetEmojiList() map[string]string { return make(map[string]string) } func (mb *MockBot) RegisterFilter(s string, f func(string) string) {} diff --git a/plugins/rpgORdie/rpgORdie.go b/plugins/rpgORdie/rpgORdie.go index d922f55..7320046 100644 --- a/plugins/rpgORdie/rpgORdie.go +++ b/plugins/rpgORdie/rpgORdie.go @@ -1,42 +1,115 @@ package rpgORdie import ( + "fmt" "strings" - "time" "github.com/velour/catbase/bot" "github.com/velour/catbase/bot/msg" ) +const ( + DUDE = ":lion_face:" + BOULDER = ":full_moon:" + HOLE = ":new_moon:" + EMPTY = ":white_large_square:" + + OK = iota + INVALID = iota + WIN = iota +) + type RPGPlugin struct { - Bot bot.Bot - listenFor map[string]bool + Bot bot.Bot + listenFor map[string]*board +} + +type board struct { + state [][]string + x, y int +} + +func NewRandomBoard() *board { + boardSize := 5 + b := board{ + state: make([][]string, boardSize), + x: boardSize - 1, + y: boardSize - 1, + } + for i := 0; i < boardSize; i++ { + b.state[i] = make([]string, boardSize) + for j := 0; j < boardSize; j++ { + b.state[i][j] = ":white_large_square:" + } + } + + b.state[boardSize-1][boardSize-1] = DUDE + b.state[boardSize/2][boardSize/2] = BOULDER + b.state[0][0] = HOLE + + return &b +} + +func (b *board) toMessageString() string { + lines := make([]string, len(b.state)) + for i := 0; i < len(b.state); i++ { + lines[i] = strings.Join(b.state[i], "") + } + return strings.Join(lines, "\n") +} + +func (b *board) checkAndMove(dx, dy int) int { + newX := b.x + dx + newY := b.y + dy + + if newX < 0 || newY < 0 || newX >= len(b.state) || newY >= len(b.state) { + return INVALID + } + + if b.state[newY][newX] == HOLE { + return INVALID + } + + win := false + if b.state[newY][newX] == BOULDER { + newBoulderX := newX + dx + newBoulderY := newY + dy + + if newBoulderX < 0 || newBoulderY < 0 || newBoulderX >= len(b.state) || newBoulderY >= len(b.state) { + return INVALID + } + + if b.state[newBoulderY][newBoulderX] != HOLE { + b.state[newBoulderY][newBoulderX] = BOULDER + } else { + win = true + } + } + + b.state[newY][newX] = DUDE + b.state[b.y][b.x] = EMPTY + b.x = newX + b.y = newY + + if win { + return WIN + } + return OK } func New(b bot.Bot) *RPGPlugin { return &RPGPlugin{ - Bot: b, - listenFor: map[string]bool{}, + Bot: b, + listenFor: map[string]*board{}, } } func (p *RPGPlugin) Message(message msg.Message) bool { if strings.ToLower(message.Body) == "start rpg" { - ts := p.Bot.SendMessage(message.Channel, "I'll edit this.") - - p.listenFor[ts] = true - - time.Sleep(2 * time.Second) - - edited := "" - for i := 0; i <= 5; i++ { - p.Bot.Edit(message.Channel, edited, ts) - edited += ":fire:" - time.Sleep(500 * time.Millisecond) - } - p.Bot.Edit(message.Channel, "HECK YES", ts) - - p.Bot.ReplyToMessageIdentifier(message.Channel, "How's this reply?", ts) + b := NewRandomBoard() + ts := p.Bot.SendMessage(message.Channel, b.toMessageString()) + p.listenFor[ts] = b + p.Bot.ReplyToMessageIdentifier(message.Channel, "Over here.", ts) return true } return false @@ -64,8 +137,31 @@ func (p *RPGPlugin) RegisterWeb() *string { func (p *RPGPlugin) ReplyMessage(message msg.Message, identifier string) bool { if strings.ToLower(message.User.Name) != strings.ToLower(p.Bot.Config().Nick) { - if _, ok := p.listenFor[identifier]; ok { - p.Bot.ReplyToMessageIdentifier(message.Channel, "Pong", identifier) + if b, ok := p.listenFor[identifier]; ok { + + var res int + + if message.Body == "left" { + res = b.checkAndMove(-1, 0) + } else if message.Body == "right" { + res = b.checkAndMove(1, 0) + } else if message.Body == "up" { + res = b.checkAndMove(0, -1) + } else if message.Body == "down" { + res = b.checkAndMove(0, 1) + } else { + return false + } + + switch res { + case OK: + p.Bot.Edit(message.Channel, b.toMessageString(), identifier) + case WIN: + p.Bot.Edit(message.Channel, b.toMessageString(), identifier) + p.Bot.ReplyToMessageIdentifier(message.Channel, "congratulations, you beat the easiest level imaginable.", identifier) + case INVALID: + p.Bot.ReplyToMessageIdentifier(message.Channel, fmt.Sprintf("you can't move %s", message.Body), identifier) + } return true } } From 345129264bdff22743d91a41fd49416990430f14 Mon Sep 17 00:00:00 2001 From: skkiesel Date: Fri, 3 Nov 2017 14:07:30 -0400 Subject: [PATCH 8/8] use 'as_user' when sending messages and replies --- slack/slack.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/slack/slack.go b/slack/slack.go index b22f622..ade25ef 100644 --- a/slack/slack.go +++ b/slack/slack.go @@ -209,6 +209,7 @@ func (s *Slack) SendMessageType(channel, message string, meMessage bool) (string url.Values{"token": {s.config.Slack.Token}, "channel": {channel}, "text": {message}, + "as_user": {"true"}, }) if err != nil { @@ -258,6 +259,7 @@ func (s *Slack) ReplyToMessageIdentifier(channel, message, identifier string) (s url.Values{"token": {s.config.Slack.Token}, "channel": {channel}, "text": {message}, + "as_user": {"true"}, "thread_ts": {identifier}, })