-
Notifications
You must be signed in to change notification settings - Fork 57
/
remote.go
161 lines (130 loc) · 4.18 KB
/
remote.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
// SPDX-License-Identifier: Apache-2.0
package slack
import (
"time"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"github.com/slack-go/slack"
"github.com/target/flottbot/models"
"github.com/target/flottbot/remote"
)
/*
=======================================
Implementation for the Remote interface
=======================================
*/
// Client struct.
type Client struct {
ListenerPort string
Token string
AppToken string
SigningSecret string
}
// validate that Client adheres to remote interface.
var _ remote.Remote = (*Client)(nil)
// instantiate a new slack client.
func (c *Client) new() *slack.Client {
api := slack.New(c.Token)
return api
}
type slackLogger struct {
zerolog.Logger
}
// Name returns the name of the remote.
func (c *Client) Name() string {
return "slack"
}
func (l *slackLogger) Output(_ int, s string) error {
l.Logger.Info().Msg(s)
return nil
}
// Reaction implementation to satisfy remote interface.
func (c *Client) Reaction(message models.Message, rule models.Rule, _ *models.Bot) {
if rule.RemoveReaction != "" {
// Init api client
api := c.new()
// Grab a reference to the message
msgRef := slack.NewRefToMessage(message.ChannelID, message.Timestamp)
// Remove bot reaction from message
if err := api.RemoveReaction(rule.RemoveReaction, msgRef); err != nil {
log.Error().Msgf("could not add reaction: %v", err)
return
}
log.Info().Msgf("removed reaction %#q for rule %#q", rule.RemoveReaction, rule.Name)
}
if rule.Reaction != "" {
// Init api client
api := c.new()
// Grab a reference to the message
msgRef := slack.NewRefToMessage(message.ChannelID, message.Timestamp)
// React with desired reaction
if err := api.AddReaction(rule.Reaction, msgRef); err != nil {
log.Error().Msgf("could not add reaction: %v", err)
return
}
log.Info().Msgf("added reaction %#q for rule %#q", rule.Reaction, rule.Name)
}
}
// Read implementation to satisfy remote interface
// Utilizes the Slack API client to read messages from Slack.
func (c *Client) Read(inputMsgs chan<- models.Message, _ map[string]models.Rule, bot *models.Bot) {
// init api client
api := c.new()
// get bot id
rat, err := api.AuthTest()
if err != nil {
log.Error().Msgf("the 'slack_token' is invalid or is unauthorized: %s", err)
return
}
// fetch rooms async
go func(b *models.Bot) {
start := time.Now()
// get bot rooms
b.Rooms = getRooms(api)
log.Info().Msgf("fetched %d rooms in %s", len(b.Rooms), time.Since(start).String())
}(bot)
// set the bot ID
bot.ID = rat.UserID
if c.AppToken != "" {
// handle Socket Mode
// assuming Socket Mode if slack_app_token is provided
sm := slack.New(
bot.SlackToken,
slack.OptionDebug(bot.Debug),
slack.OptionAppLevelToken(c.AppToken),
// pass our custom logger through to slack
slack.OptionLog(&slackLogger{Logger: log.Logger.With().Str("mode", "socket").Logger()}),
)
// move the above inside readFromSocketMode below :o
readFromSocketMode(sm, inputMsgs, bot)
} else if c.SigningSecret != "" {
// handle Events API setup
// assuming Events API setup if slack_signing_secret is provided
readFromEventsAPI(api, c.SigningSecret, inputMsgs, bot)
}
// slack is not configured correctly and cli is set to false
// TODO: move this out of the remote setup
if c.AppToken == "" && c.SigningSecret == "" && !bot.CLI {
log.Error().Msg("cli mode is disabled and tokens are not set up correctly to run the bot")
}
}
// Send implementation to satisfy remote interface.
func (c *Client) Send(message models.Message, _ *models.Bot) {
log.Debug().Msgf("sending message %#q", message.ID)
api := c.new()
// check message size and trim if necessary because
// slack messages have a hard limit of 4000 characters
if len(message.Output) > slack.MaxMessageTextLength {
contents := message.Output
message.Output = contents[:(slack.MaxMessageTextLength-3)] + "..."
}
// Timestamp message
message.EndTime = models.MessageTimestamp()
// send message based on type
switch message.Type {
case models.MsgTypeDirect, models.MsgTypeChannel, models.MsgTypePrivateChannel:
send(api, message)
default:
log.Warn().Msg("received unknown message type - no message to send")
}
}