Skip to content

Commit 32478e1

Browse files
committed
Use SocketMode for connections
Updates Slacker to use the Events API over the SocketMode communication protocol, replacing calls to the deprecated RTM API. A few key functions have changed, notably the NewClient function now requires both an App and Bot token to be specified. In addition, the typing indicator is not supported in SocketMode and has been removed altogether.
1 parent 450dc60 commit 32478e1

File tree

4 files changed

+236
-167
lines changed

4 files changed

+236
-167
lines changed

analytics.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,15 @@ import (
44
"time"
55

66
"github.com/shomali11/proper"
7-
"github.com/slack-go/slack"
87
)
98

109
// NewCommandEvent creates a new command event
11-
func NewCommandEvent(command string, parameters *proper.Properties, message *slack.MessageEvent) *CommandEvent {
10+
func NewCommandEvent(command string, parameters *proper.Properties, event *MessageEvent) *CommandEvent {
1211
return &CommandEvent{
1312
Timestamp: time.Now(),
1413
Command: command,
1514
Parameters: parameters,
16-
Message: message,
15+
Event: event,
1716
}
1817
}
1918

@@ -22,5 +21,5 @@ type CommandEvent struct {
2221
Timestamp time.Time
2322
Command string
2423
Parameters *proper.Properties
25-
Message *slack.MessageEvent
24+
Event *MessageEvent
2625
}

context.go

Lines changed: 61 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,27 @@ import (
44
"context"
55

66
"github.com/slack-go/slack"
7+
"github.com/slack-go/slack/socketmode"
78
)
89

910
// A BotContext interface is used to respond to an event
1011
type BotContext interface {
1112
Context() context.Context
12-
Event() *slack.MessageEvent
13-
RTM() *slack.RTM
13+
Event() *MessageEvent
14+
SocketMode() *socketmode.Client
1415
Client() *slack.Client
1516
}
1617

1718
// NewBotContext creates a new bot context
18-
func NewBotContext(ctx context.Context, event *slack.MessageEvent, client *slack.Client, rtm *slack.RTM) BotContext {
19-
return &botContext{ctx: ctx, event: event, client: client, rtm: rtm}
19+
func NewBotContext(ctx context.Context, client *slack.Client, socketmode *socketmode.Client, evt *MessageEvent) BotContext {
20+
return &botContext{ctx: ctx, event: evt, client: client, socketmode: socketmode}
2021
}
2122

2223
type botContext struct {
23-
ctx context.Context
24-
event *slack.MessageEvent
25-
client *slack.Client
26-
rtm *slack.RTM
24+
ctx context.Context
25+
event *MessageEvent
26+
client *slack.Client
27+
socketmode *socketmode.Client
2728
}
2829

2930
// Context returns the context
@@ -32,16 +33,64 @@ func (r *botContext) Context() context.Context {
3233
}
3334

3435
// Event returns the slack message event
35-
func (r *botContext) Event() *slack.MessageEvent {
36+
func (r *botContext) Event() *MessageEvent {
3637
return r.event
3738
}
3839

39-
// RTM returns the RTM client
40-
func (r *botContext) RTM() *slack.RTM {
41-
return r.rtm
40+
// SocketMode returns the SocketMode client
41+
func (r *botContext) SocketMode() *socketmode.Client {
42+
return r.socketmode
4243
}
4344

4445
// Client returns the slack client
4546
func (r *botContext) Client() *slack.Client {
4647
return r.client
4748
}
49+
50+
// MessageEvent contains details common to message based events, including the
51+
// raw event as returned from Slack along with the corresponding event type.
52+
// The struct should be kept minimal and only include data that is commonly
53+
// used to prevent freqeuent type assertions when evaluating the event.
54+
type MessageEvent struct {
55+
// Channel ID where the message was sent
56+
Channel string
57+
58+
// User ID of the sender
59+
User string
60+
61+
// Text is the unalterted text of the message, as returned by Slack
62+
Text string
63+
64+
// TimeStamp is the message timestamp
65+
TimeStamp string
66+
67+
// ThreadTimeStamp is the message thread timestamp.
68+
ThreadTimeStamp string
69+
70+
// Data is the raw event data returned from slack. Using Type, you can assert
71+
// this into a slackevents *Event struct.
72+
Data interface{}
73+
74+
// Type is the type of the event, as returned by Slack. For instance,
75+
// `app_mention` or `message`
76+
Type string
77+
78+
// BotID holds the Slack User ID for our bot
79+
BotID string
80+
}
81+
82+
// IsThread indicates if a message event took place in a thread.
83+
func (e *MessageEvent) IsThread() bool {
84+
if e.ThreadTimeStamp == "" || e.ThreadTimeStamp == e.TimeStamp {
85+
return false
86+
}
87+
return true
88+
}
89+
90+
// IsBot indicates if the message was sent by a bot
91+
func (e *MessageEvent) IsBot() bool {
92+
if e.BotID == "" {
93+
return false
94+
}
95+
return true
96+
}

response.go

Lines changed: 24 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ const (
1414
type ResponseWriter interface {
1515
Reply(text string, options ...ReplyOption) error
1616
ReportError(err error, options ...ReportErrorOption)
17-
Typing()
1817
}
1918

2019
// NewResponse creates a new response structure
@@ -30,56 +29,43 @@ type response struct {
3029
func (r *response) ReportError(err error, options ...ReportErrorOption) {
3130
defaults := newReportErrorDefaults(options...)
3231

33-
rtm := r.botCtx.RTM()
34-
event := r.botCtx.Event()
35-
message := rtm.NewOutgoingMessage(fmt.Sprintf(errorFormat, err.Error()), event.Channel)
32+
client := r.botCtx.Client()
33+
ev := r.botCtx.Event()
34+
35+
opts := []slack.MsgOption{
36+
slack.MsgOptionText(fmt.Sprintf(errorFormat, err.Error()), false),
37+
}
3638
if defaults.ThreadResponse {
37-
message.ThreadTimestamp = event.ThreadTimestamp
38-
if event.ThreadTimestamp == "" {
39-
message.ThreadTimestamp = event.EventTimestamp
40-
}
39+
opts = append(opts, slack.MsgOptionTS(ev.TimeStamp))
40+
}
41+
_, _, err = client.PostMessage(ev.Channel, opts...)
42+
if err != nil {
43+
fmt.Printf("failed posting message: %v\n", err)
4144
}
42-
43-
rtm.SendMessage(message)
44-
}
45-
46-
// Typing send a typing indicator
47-
func (r *response) Typing() {
48-
rtm := r.botCtx.RTM()
49-
event := r.botCtx.Event()
50-
rtm.SendMessage(rtm.NewTypingMessage(event.Channel))
5145
}
5246

5347
// Reply send a attachments to the current channel with a message
5448
func (r *response) Reply(message string, options ...ReplyOption) error {
5549
defaults := newReplyDefaults(options...)
5650

57-
rtm := r.botCtx.RTM()
58-
event := r.botCtx.Event()
59-
if defaults.ThreadResponse {
60-
threadTimestamp := event.ThreadTimestamp
61-
if event.ThreadTimestamp == "" {
62-
threadTimestamp = event.EventTimestamp
63-
}
64-
_, _, err := rtm.PostMessage(
65-
event.Channel,
66-
slack.MsgOptionText(message, false),
67-
slack.MsgOptionUser(rtm.GetInfo().User.ID),
68-
slack.MsgOptionAsUser(true),
69-
slack.MsgOptionAttachments(defaults.Attachments...),
70-
slack.MsgOptionBlocks(defaults.Blocks...),
71-
slack.MsgOptionTS(threadTimestamp),
72-
)
73-
return err
51+
client := r.botCtx.Client()
52+
ev := r.botCtx.Event()
53+
if ev == nil {
54+
return fmt.Errorf("Unable to get message event details")
7455
}
7556

76-
_, _, err := rtm.PostMessage(
77-
event.Channel,
57+
opts := []slack.MsgOption{
7858
slack.MsgOptionText(message, false),
79-
slack.MsgOptionUser(rtm.GetInfo().User.ID),
80-
slack.MsgOptionAsUser(true),
8159
slack.MsgOptionAttachments(defaults.Attachments...),
8260
slack.MsgOptionBlocks(defaults.Blocks...),
61+
}
62+
if defaults.ThreadResponse {
63+
opts = append(opts, slack.MsgOptionTS(ev.TimeStamp))
64+
}
65+
66+
_, _, err := client.PostMessage(
67+
ev.Channel,
68+
opts...,
8369
)
8470
return err
8571
}

0 commit comments

Comments
 (0)