forked from cee-studio/orca
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathslack-socketmode.c
177 lines (139 loc) · 4.45 KB
/
slack-socketmode.c
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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "slack.h"
#include "slack-internal.h"
#include "orka-utils.h"
static void
apps_connections_open_from_json(char str[], size_t len, void *p_url)
{
bool status = false;
struct sized_buffer metadata = {0}, messages = {0};
json_extract(str, len,
"(ok):b"
"(url):s"
"(response_metadata):T",
&status,
(char*)p_url,
&metadata);
if (metadata.start) {
json_extract(metadata.start, metadata.size, "(messages):T", &messages);
}
VASSERT_S(true == status, "Couldn't fetch connections for websockets:\n\t\tMessage: %.*s", (int)messages.size, messages.start);
}
void
slack_apps_connections_open(struct slack *client)
{
ASSERT_S(NULL != client->bot_token.start, "Missing bot token");
ASSERT_S(NULL != client->app_token.start, "Missing app token");
char auth[128];
int ret = snprintf(auth, sizeof(auth), "Bearer %.*s", (int)client->app_token.size, client->app_token.start);
ASSERT_S(ret < sizeof(auth), "Out of bounds write attempt");
ua_reqheader_add(client->adapter.ua, "Authorization", auth);
struct ua_resp_handle resp_handle = { .ok_cb = &apps_connections_open_from_json, .ok_obj = client->sm.base_url };
slack_adapter_run(
&client->adapter,
&resp_handle,
NULL,
HTTP_POST, "/apps.connections.open");
ret = snprintf(auth, sizeof(auth), "Bearer %.*s", (int)client->bot_token.size, client->bot_token.start);
ASSERT_S(ret < sizeof(auth), "Out of bounds write attempt");
ua_reqheader_add(client->adapter.ua, "Authorization", auth);
}
static void
on_hello(struct slack_socketmode *sm)
{
struct slack *client = sm->p_client;
sm->is_ready = true;
if (!client->cbs.on_hello) return;
(*client->cbs.on_hello)(client, sm->text.payload.start, sm->text.payload.size);
}
static void
on_message(struct slack_socketmode *sm, struct sized_buffer *event)
{
if (!sm->p_client->cbs.on_message) return;
(*sm->p_client->cbs.on_message)(sm->p_client, event->start, event->size);
}
static void
on_events_api(struct slack_socketmode *sm)
{
struct sized_buffer t_event = {0}, t_type = {0};
json_extract(sm->text.payload.start, sm->text.payload.size,
"(event):T", &t_event);
if (t_event.start) {
json_extract(t_event.start, t_event.size, "(type):T", &t_type);
}
if (STRNEQ("message", t_type.start, sizeof("message")-1))
on_message(sm, &t_event);
}
static void
on_connect_cb(void *p_sm, const char *ws_protocols) {
log_info("Connected, WS-Protocols: '%s'", ws_protocols);
}
static void
on_text_cb(void *p_sm, const char *text, size_t len)
{
struct slack_socketmode *sm = p_sm;
log_trace("ON_EVENT:\t%s", text);
json_extract((char*)text, len,
"(payload):T"
"(envelope_id):s"
"(type):s"
"(accepts_response_payload):b",
&sm->text.payload,
sm->text.envelope_id,
sm->text.type,
&sm->text.accepts_response_payload);
// @todo just two events for testing purposes
if (STREQ(sm->text.type, "hello"))
on_hello(sm);
if (STREQ(sm->text.type, "events_api"))
on_events_api(sm);
}
static void
on_close_cb(void *p_sm, enum ws_close_reason wscode, const char *reason, size_t len)
{
struct slack_socketmode *sm = p_sm;
log_warn("\n\t(code: %4d) : %zd bytes\n\t"
"REASON: '%s'",
wscode, len, reason);
sm->is_ready = false; // reset
}
void
slack_socketmode_init(struct slack_socketmode *sm, struct logconf *config)
{
ASSERT_S(NULL != sm->p_client, "Not meant to be called standalone");
slack_apps_connections_open(sm->p_client);
struct ws_callbacks cbs = {
.data = sm,
.on_connect = &on_connect_cb,
.on_text = &on_text_cb,
.on_close = &on_close_cb
};
// @todo temporary debug_reconnect while development phase
strncat(sm->base_url, "&debug_reconnects=true", sizeof(sm->base_url));
sm->ws = ws_init(&cbs, config);
ws_set_url(sm->ws, sm->base_url, NULL);
logconf_add_id(config, sm->ws, "SLACK_SOCKETMODE");
}
void
slack_socketmode_cleanup(struct slack_socketmode *sm) {
ws_cleanup(sm->ws);
}
/* connects to the slack websockets server */
void
slack_socketmode_run(struct slack *client)
{
struct slack_socketmode *sm = &client->sm;
ASSERT_S(WS_DISCONNECTED == ws_get_status(sm->ws), "Can't run websockets recursively");
bool is_running;
do {
ws_perform(sm->ws, &is_running, 1);
if (!sm->is_ready) continue;
// connection established
} while (is_running);
}
void
slack_socketmode_shutdown(struct slack *client) {
/// @todo
}