-
Notifications
You must be signed in to change notification settings - Fork 3
/
bot_events.go
96 lines (84 loc) · 2.64 KB
/
bot_events.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
package websockets
import (
"context"
"encoding/json"
"github.com/slack-go/slack/socketmode"
"go.uber.org/zap"
"go.autokitteh.dev/autokitteh/integrations/slack/events"
"go.autokitteh.dev/autokitteh/integrations/slack/internal/vars"
"go.autokitteh.dev/autokitteh/integrations/slack/webhooks"
"go.autokitteh.dev/autokitteh/internal/kittehs"
"go.autokitteh.dev/autokitteh/sdk/sdktypes"
)
// HandleBotEvent routes all asynchronous bot event notifications that our Slack
// app subscribed to, to specific event handlers based on the event type.
// See https://api.slack.com/apis/connections/events-api#responding.
// Compare this function with the [webhooks.HandleBotEvent] implementation.
func (h handler) handleBotEvent(e *socketmode.Event, c *socketmode.Client) {
defer c.Ack(*e.Request)
// Reuse the Slack event's JSON payload instead of the struct.
body, err := e.Request.Payload.MarshalJSON()
if err != nil {
h.logger.Error("Bad request from Slack websocket",
zap.Any("payload", e.Request.Payload),
)
return
}
// Parse the inbound request (no need to validate authenticity, unlike webhooks).
cb := &events.Callback{}
if err := json.Unmarshal(body, cb); err != nil {
h.logger.Error("Failed to parse bot event's JSON payload",
zap.ByteString("json", body),
zap.Error(err),
)
return
}
// Parse the received event's inner details based on its type.
t := cb.Type
if t == "event_callback" {
t = cb.Event.Type
}
l := h.logger.With(zap.String("event", t))
f, ok := webhooks.BotEventHandlers[t]
if !ok {
l.Error("Received unsupported bot event",
zap.ByteString("body", body),
zap.Any("callback", cb),
)
return
}
slackEvent := f(l, nil, body, cb)
if slackEvent == nil {
return
}
// Transform the received Slack event into an autokitteh event.
wrapped, err := sdktypes.DefaultValueWrapper.Wrap(slackEvent)
if err != nil {
h.logger.Error("Failed to wrap Slack event",
zap.Any("cmd", slackEvent),
zap.Error(err),
)
return
}
m, err := wrapped.ToStringValuesMap()
if err != nil {
h.logger.Error("Failed to convert wrapped Slack event",
zap.Any("event", slackEvent),
zap.Error(err),
)
return
}
pb := kittehs.TransformMapValues(m, sdktypes.ToProto)
akEvent := &sdktypes.EventPB{
EventType: cb.Event.Type,
Data: pb,
}
// Retrieve all the relevant connections for this event.
cids, err := h.vars.FindConnectionIDs(context.Background(), h.integrationID, vars.AppTokenName, "")
if err != nil {
h.logger.Error("Failed to retrieve connection tokens", zap.Error(err))
return
}
// Dispatch the event to all of them, for asynchronous handling.
h.dispatchAsyncEventsToConnections(cids, akEvent)
}