Files
Aurora.3/code/datums/discord_bot.dm
skull132 759c463a2c BOREALIS 2 Implementation (#938)
Removes BOREALIS I.
Implements HTTP POST requests, credit to Oisin100 from Yogstation13 for the ByondPOST.dll.
Implements the BOREALIS II datum and converts all calls to reroute to that.
Adds round logging to channel_announce channels.
2016-09-18 23:28:01 +03:00

156 lines
3.7 KiB
Plaintext

#define CHAN_ADMIN "channel_admin"
#define CHAN_CCIAA "channel_cciaa"
#define CHAN_ANNOUNCE "channel_announce"
var/datum/discord_bot/discord_bot = null
/hook/startup/proc/initialize_discord_bot()
if (discord_bot)
// This shouldn't be possible, but sure!
return 0
discord_bot = new()
config.load("config/discord.txt", "discord")
discord_bot.update_channels()
return 1
/datum/discord_bot
var/list/channels = list()
var/active = 0
var/auth_token = ""
var/robust_debug = 0
// Lazy man's rate limiting vars
var/rate_limited_since = 0
var/queue_being_pushed = 0
var/list/queue = list()
/datum/discord_bot/proc/update_channels()
if (!active)
return 1
if (!establish_db_connection(dbcon))
log_debug("BOREALIS: Failed to update channels due to missing database.")
return 2
channels = list()
var/DBQuery/channel_query = dbcon.NewQuery("SELECT channel_group, channel_id FROM discord_channels")
channel_query.Execute()
var/list/A
while (channel_query.NextRow())
if (isnull(channels[channel_query.item[1]]))
channels[channel_query.item[1]] = list()
A = channels[channel_query.item[1]]
A += channel_query.item[2]
log_debug("BOREALIS: Channels updated successfully.")
return 0
/datum/discord_bot/proc/send_message(var/channel_group, var/message)
if (!active || !auth_token)
return
if (!channel_group || !channels.len || isnull(channels[channel_group]))
return
if (!message)
return
if (length(message) > 2000)
message = copytext(message, 1, 2001)
// Let's run it through the proper JSON encoder, just in case of special characters.
message = json_encode(list("content" = message))
var/list/A = channels[channel_group]
var/list/sent = list()
for (var/channel in A)
if (send_post_request("https://discordapp.com/api/channels/[channel]/messages", message, "Authorization: Bot [auth_token]", "Content-Type: application/json") == 429)
// Whoopsies, rate limited.
// Set up the queue.
rate_limited_since = world.time
queue.Add(list(message, A - sent))
// Schedule a push.
spawn (100)
push_queue()
// And exit.
return
else
sent += channel
if (robust_debug)
log_debug("BOEALIS: Message sent to [channel_group]. JSON body: '[message]'")
/datum/discord_bot/proc/send_to_admins(message)
send_message(CHAN_ADMIN, message)
/datum/discord_bot/proc/send_to_cciaa(message)
send_message(CHAN_CCIAA, message)
/datum/discord_bot/proc/send_to_announce(message)
send_message(CHAN_ANNOUNCE, message)
/datum/discord_bot/proc/push_queue()
// What facking queue.
if (!queue.len)
if (robust_debug)
log_debug("BOREALIS: Attempted to push a null length queue.")
if (queue_being_pushed)
queue_being_pushed = 0
return
if (queue_being_pushed)
if (robust_debug)
log_debug("BOREALIS: Attempted to initialize a second queue driver.")
return
if ((world.time - rate_limited_since) < 100)
// Something broke the limit again. Ideally, this wouldn't happen. But sure.
// Use a longer timeout, just in case.
spawn (200)
push_queue()
queue_being_pushed = 0
return
// Async process lock var. No touchy.
queue_being_pushed = 1
// A[1] - message body.
// A[2] - list of channels to send to.
var/message
var/list/destinations
for (var/list/A in queue)
message = A[1]
destinations = A[2]
for (var/channel in destinations)
if (send_post_request("https://discordapp.com/api/channels/[channel]/messages", message, "Authorization: Bot [auth_token]", "Content-Type: application/json") == 429)
// Limited again. Reschedule.
rate_limited_since = world.time
spawn (100)
push_queue()
queue_being_pushed = 0
return
else
destinations.Remove(channel)
queue.Remove(A)
queue_being_pushed = 0
#undef CHAN_ADMIN
#undef CHAN_CCIAA
#undef CHAN_ANNOUNCE