-
Notifications
You must be signed in to change notification settings - Fork 2
/
app.d
140 lines (115 loc) · 4.4 KB
/
app.d
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
/*******************************************************************************
Simple example of a Slack bot which just answers when mentioned
Author: Mathias 'Geod24' Lang
License: MIT (See LICENSE.txt)
Copyright: Copyright (c) 2016-2017 Mathias Lang. All rights reserved.
*******************************************************************************/
module simple.app;
import std.exception;
import vibe.core.args;
import vibe.core.core;
import vibe.core.log;
import vibe.data.json;
import vibe.http.client;
import vibe.http.websockets;
import vibe.stream.tls;
import slacklib.Client;
import slacklib.Message;
import slacklib.Utils;
/// Initialization (used by Vibe.d)
shared static this ()
{
string auth_token;
readOption("auth-token", &auth_token,
"Token to use for authentication on the web API");
runTask(() => startBot(auth_token));
}
/// Start the bot's event loop
private void startBot (string auth_token)
{
HTTPClient.setTLSSetupCallback(&disablePerrValidation);
logInfo("Starting up connection...");
auto client = Client.start(auth_token);
logInfo("WebSocket connected");
client.runEventLoop(); // Should never return
logFatal("Connection to Slack lost!");
}
void disablePerrValidation (TLSContext context) @safe
{
context.peerValidationMode = TLSPeerValidationMode.none;
}
///
public class Client : SlackClient
{
/***************************************************************************
Given an authentication token, starts a new connection to Slack's
real-time-messaging (RTM) API.
***************************************************************************/
public static SlackClient start (string token)
{
enforce(token.length, "Empty token provided");
Json infos;
auto auth = "Bearer " ~ token;
/*SlackClient.*/webr("rtm.connect", auth).request(
(scope HTTPClientResponse res) { infos = res.readJson; });
scope (failure)
logError("Error while connecting to Slack: %s", infos.to!string);
enforce(infos["ok"].get!bool, "Slack didn't answer with 'ok=true'");
logInfo("Response from slack: %s", infos.to!string);
auto sock = connectWebSocket(URL(infos["url"].get!istring));
auto hello_msg = sock.receiveText();
auto msg = parseJsonString(hello_msg);
enforce(msg["type"].get!string == `hello`,
"Expected 'hello' message, but got: " ~ hello_msg);
return new Client(token, sock, infos);
}
/***************************************************************************
Private ctor, called from `start`
***************************************************************************/
private this (string token, WebSocket socket, Json infos)
{
super(token, socket, infos);
}
/// Implementation of the handler
protected override void handleEvent (Json msg) nothrow
{
try handle(msg);
catch (Exception e)
logError("Error happened while handling '%s': %s", msg, e);
}
/// Just log received messages and pretty-print messages
public void handle (Json json)
{
import std.algorithm.searching : any;
logInfo("Received: %s", json);
auto type = enforce("type" in json, "No type in json");
if (type.to!string == "pong")
return;
if (type.to!string == "message")
{
if (auto st = "subtype" in json) {
logInfo("Ignoring message with subtype %s", st.to!string);
return;
}
auto msg = enforce("text" in json, "No text for message").to!string;
/// Usage of the 'mentions' helper
if (msg.mentions.any!((v) => v == this.id))
{
logInfo("I was mentioned! Message: %s", msg);
if (auto chan = "channel" in json)
{
if (auto user = "user" in json)
{
this.sendMessage(
(*chan).to!string,
"Thanks for your kind words <@" ~ (*user).to!string ~ ">");
}
else
logFatal("Couldn't find user: %s", json.to!string);
}
else
logError("Couldn't find channel: %s", json.to!string);
}
}
}
}