#include "discord_client.h" #include DiscordClient::DiscordClient(uv_loop_t *loop, std::string token) : m_eventLoop(loop), m_botToken(token) {} DiscordClient::~DiscordClient() { stop(); } // TODO make asynchronous bool DiscordClient::start() { if (m_running) return false; m_running = true; spdlog::debug("discord: start"); m_eventHandle = new uv_async_t; m_eventHandle->data = this; uv_async_init(m_eventLoop, m_eventHandle, DiscordClient::uv_callback); m_bot = std::make_unique(m_botToken); try { m_bot->start(true); } catch (int e) { spdlog::debug("discord: start failed"); return false; } m_bot->on_ready([this](const dpp::ready_t &event) { spdlog::debug("discord: ready, registering commands"); dpp::slashcommand command("shorten", "Shorten a URL", m_bot->me.id); command.add_option(dpp::command_option(dpp::co_string, std::string("url"), std::string("URL"), true)); std::vector commands { command }; m_bot->global_bulk_command_create(commands, [](const dpp::confirmation_callback_t &e) { if (!e.is_error()) { spdlog::info("discord: register commands success"); } else { spdlog::error("discord: register commands failure: {}", e.get_error().message); } }); }); m_bot->on_slashcommand([this](const dpp::slashcommand_t &event) { auto cmdname = event.command.get_command_name(); if (cmdname == "shorten") { dpp::slashcommand_t eventCopy = event; eventCopy.thinking(); spdlog::debug("discord: received /shorten comand"); std::string url = std::get(event.get_parameter("url")); m_commandQueueMutex.lock(); m_commandQueue.push(std::move(BotCommand(ShortenCommand {url, std::move(event)}))); m_commandQueueMutex.unlock(); uv_async_send(m_eventHandle); } else { spdlog::warn("discord: received unknown command {}", cmdname); } }); return true; } void DiscordClient::uv_callback(uv_async_t *h) { auto self = reinterpret_cast(h->data); self->m_commandQueueMutex.lock(); while (!self->m_commandQueue.empty()) { BotCommand nextCmd = std::move(self->m_commandQueue.front()); self->m_commandQueue.pop(); switch (nextCmd.type) { case BotCommandType::SHORTEN: if (self->on_shorten_command) self->on_shorten_command(nextCmd.shortenCmd.url, nextCmd.shortenCmd.event); break; } } self->m_commandQueueMutex.unlock(); } bool DiscordClient::stop() { if (!m_running) return false; m_running = false; m_bot->shutdown(); uv_close((uv_handle_t*)m_eventHandle, [](uv_handle_t *h){ delete h; }); return true; } BotCommand::BotCommand(ShortenCommand &&cmd) : type(BotCommandType::SHORTEN), shortenCmd(cmd) {} BotCommand::BotCommand(BotCommand &&other) { type = other.type; switch (other.type) { case BotCommandType::SHORTEN: new (&shortenCmd) ShortenCommand(other.shortenCmd); break; } } BotCommand::~BotCommand() { switch (type) { case BotCommandType::SHORTEN: shortenCmd.~ShortenCommand(); break; } }