diff options
-rw-r--r-- | 142bot.config.in | 6 | ||||
-rw-r--r-- | CMakeLists.txt | 18 | ||||
-rw-r--r-- | include/142bot/bot.hpp | 2 | ||||
-rw-r--r-- | include/142bot/modules.hpp | 7 | ||||
-rw-r--r-- | modules/mmanager/mmanager.cpp | 250 | ||||
-rw-r--r-- | modules/reactions/reactions.cpp | 5 | ||||
-rw-r--r-- | modules/spotify/spotify.cpp | 1 | ||||
-rw-r--r-- | src/bot.cpp | 4 | ||||
-rw-r--r-- | src/db.cpp | 7 | ||||
-rw-r--r-- | src/main.cpp | 17 |
10 files changed, 247 insertions, 70 deletions
diff --git a/142bot.config.in b/142bot.config.in new file mode 100644 index 0000000..ce28daa --- /dev/null +++ b/142bot.config.in @@ -0,0 +1,6 @@ +// MODIFIED BY CMAKE +// + +#define onefortytwobot_VERSION_MAJOR @onefortytwobot_VERSION_MAJOR@ +#define onefortytwobot_VERSION_MINOR @onefortytwobot_VERSION_MINOR@ +#define onefortytwobot_env "@CMAKE_BUILD_TYPE@"
\ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index f26e300..3192505 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.0) -project(142-bot VERSION 0.1 LANGUAGES CXX C) +project(onefortytwobot VERSION 0.1 LANGUAGES CXX C) set(CMAKE_CXX_STANDARD 20 REQUIRED) @@ -24,8 +24,13 @@ FetchContent_Declare(spdlog GIT_REPOSITORY https://github.com/gabime/spdlog GIT_TAG v1.1.0 ) + +FetchContent_Declare(sentry + GIT_REPOSITORY https://github.com/getsentry/sentry-native + GIT_TAG 0.6.1 +) -FetchContent_MakeAvailable(clog dpp cpr fmt spdlog) +FetchContent_MakeAvailable(clog dpp cpr fmt spdlog sentry) include(cmake/FindPCRE.cmake) @@ -36,13 +41,16 @@ string(ASCII 27 Esc) find_library(PQXX_LIB pqxx) find_library(PQ_LIB pq) +# Define configuration file +configure_file(142bot.config.in 142bot_config.h) + include(GNUInstallDirs) aux_source_directory("src" coresrc) add_executable(142bot ${coresrc}) -include_directories("include") +include_directories("include" ${PROJECT_BINARY_DIR}) target_link_libraries(142bot PRIVATE clog dpp fmt::fmt spdlog::spdlog pcre - cpr::cpr ${PQXX_LIB} ${PQ_LIB}) + cpr::cpr ${PQXX_LIB} ${PQ_LIB} sentry) add_dependencies(142bot clog dpp cpr fmt spdlog) install(TARGETS 142bot) @@ -56,7 +64,7 @@ foreach (fullmodname ${subdirlist}) aux_source_directory(${modules_dir}/${modname} modsrc) add_library(module_${modname} SHARED ${modsrc}) add_dependencies(module_${modname} dpp cpr spdlog fmt) - target_link_libraries(module_${modname} dpp cpr) + target_link_libraries(module_${modname} dpp cpr sentry) install(TARGETS module_${modname} RUNTIME DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}/142bot/") set_target_properties(module_${modname} PROPERTIES PREFIX "") endforeach(fullmodname) diff --git a/include/142bot/bot.hpp b/include/142bot/bot.hpp index a422416..165515f 100644 --- a/include/142bot/bot.hpp +++ b/include/142bot/bot.hpp @@ -9,12 +9,12 @@ class Module; class ModuleLoader; class Bot { - pqxx::connection conn; bool dev; dpp::snowflake owner_id; private: bool run_database_migrations(); public: + pqxx::connection conn; class dpp::cluster * core; /* The bot's user from the ready event */ dpp::user user; diff --git a/include/142bot/modules.hpp b/include/142bot/modules.hpp index 3af0253..c0aad32 100644 --- a/include/142bot/modules.hpp +++ b/include/142bot/modules.hpp @@ -8,6 +8,7 @@ #pragma once #include "bot.hpp" +#include <sentry.h> class ModuleLoader; class Module; @@ -77,10 +78,16 @@ enum Events list_to_call = loader->EventHandlers[y]; \ break; \ } \ + sentry_remove_tag("module"); \ } \ catch (std::exception& modexcept) \ { \ core->log(dpp::ll_error, fmt::format("Exception caught in module: {}", modexcept.what())); \ + sentry_value_t event = sentry_value_new_event(); \ + sentry_value_t exc = sentry_value_new_exception("Exception", modexcept.what()); \ + sentry_value_set_stacktrace(exc, NULL, 0); \ + sentry_event_add_exception(event, exc); \ + sentry_capture_event(event); \ } \ } \ }; diff --git a/modules/mmanager/mmanager.cpp b/modules/mmanager/mmanager.cpp index 1a012f9..19def28 100644 --- a/modules/mmanager/mmanager.cpp +++ b/modules/mmanager/mmanager.cpp @@ -3,7 +3,7 @@ * * Filename: mmanager.cpp * - * Description: + * Description: * * Version: 1.0 * Created: 03/30/2023 11:30:55 AM @@ -23,134 +23,258 @@ #include <pcre.h> #include <dpp/dpp.h> #include <fmt/format.h> +using namespace fmt; -class MManagerModule : public Module { +class MManagerModule : public Module +{ double microseconds_ping; + public: - MManagerModule(Bot* creator, ModuleLoader* ml) : Module(creator, ml) { - ml->attach({ I_OnMessage, I_OnReady }, this); - creator->core->log(dpp::ll_info, "ModuleManager online!"); + MManagerModule(Bot *creator, ModuleLoader *ml) : Module(creator, ml) + { + ml->attach({I_OnMessage, I_OnReady}, this); + creator->core->log(dpp::ll_info, "ModuleManager online!"); } - virtual std::string version() { + virtual std::string version() + { return "0.1.0"; } - virtual std::string description() { + virtual std::string description() + { return "module manager"; } - virtual bool OnReady(const dpp::ready_t &ready) { + virtual bool OnReady(const dpp::ready_t &ready) + { bot->core->log(dpp::ll_info, "Got ready event"); return true; } - virtual bool OnMessage(const dpp::message_create_t &message, const std::string& clean_message, bool mentioned, const std::vector<std::string> &stringmentions) { - std::vector<std::string> param; - const char* pcre_error; - int pcre_error_ofs; + virtual bool OnMessage(const dpp::message_create_t &message, const std::string &clean_message, bool mentioned, const std::vector<std::string> &stringmentions) + { + sentry_set_tag("module", "mmanager"); + std::vector<std::string> param; + const char *pcre_error; + int pcre_error_ofs; auto comp = pcre_compile(std::string("^sudo(\\s+(.+?))$").c_str(), PCRE_CASELESS | PCRE_MULTILINE, &pcre_error, &pcre_error_ofs, NULL); - if (!comp) { + if (!comp) + { bot->core->log(dpp::ll_error, pcre_error); } int matcharr[90]; int matchcount = pcre_exec(comp, NULL, clean_message.c_str(), clean_message.length(), 0, 0, matcharr, 90); - for (int i = 0; i < matchcount; ++i) { + for (int i = 0; i < matchcount; ++i) + { param.push_back(std::string(clean_message.c_str() + matcharr[2 * i], (size_t)(matcharr[2 * i + 1] - matcharr[2 * i]))); } - if (mentioned && matchcount > 0) { - if (message.msg.author.id == bot->get_owner_id()) { + if (mentioned && matchcount > 0) + { + if (message.msg.author.id == bot->get_owner_id()) + { // Tokenize - for (int i = 0; i < param.size(); i++) { + for (int i = 0; i < param.size(); i++) + { bot->core->log(dpp::ll_debug, fmt::format("{}", param[i])); } std::stringstream tokens(trim(param[2])); std::string subcommand; tokens >> subcommand; - bot->core->log(dpp::ll_warning, fmt::format("SUDO: <{}> {}",message.msg.author.username, clean_message)); + bot->core->log(dpp::ll_warning, fmt::format("SUDO: <{}> {}", message.msg.author.username, clean_message)); + sentry_value_t crumb = sentry_value_new_breadcrumb("user", "got sudo command"); + sentry_value_set_by_key(crumb, "level", sentry_value_new_string("warning")); + sentry_value_set_by_key(crumb, "category", sentry_value_new_string("sudo")); + sentry_value_set_by_key(crumb, "data", sentry_value_new_string(subcommand.c_str())); + sentry_add_breadcrumb(crumb); - if (lowercase(subcommand) == "modules") { - std::stringstream s; + if (lowercase(subcommand) == "modules") + { + std::stringstream s; - // NOTE: GetModuleList's reference is safe from within a module event - const ModuleMap& modlist = bot->loader->get_loaded_modules(); + // NOTE: GetModuleList's reference is safe from within a module event + const ModuleMap &modlist = bot->loader->get_loaded_modules(); - s << "```diff" << std::endl; - s << fmt::format("╭─────────────────────────┬───────────┬────────────────────────────────────────────────╮") << std::endl; - s << fmt::format("│ Filename | Version | Description |") << std::endl; - s << fmt::format("├─────────────────────────┼───────────┼────────────────────────────────────────────────┤") << std::endl; + s << "```diff" << std::endl; + s << fmt::format("╭─────────────────────────┬───────────┬────────────────────────────────────────────────╮") << std::endl; + s << fmt::format("│ Filename | Version | Description |") << std::endl; + s << fmt::format("├─────────────────────────┼───────────┼────────────────────────────────────────────────┤") << std::endl; - for (auto mod = modlist.begin(); mod != modlist.end(); ++mod) { - s << fmt::format("│ {:23} | {:9} | {:46} |", mod->first, mod->second->version(), mod->second->description()) << std::endl; - } - s << fmt::format("╰─────────────────────────┴───────────┴────────────────────────────────────────────────╯") << std::endl; - s << "```"; + for (auto mod = modlist.begin(); mod != modlist.end(); ++mod) + { + s << fmt::format("│ {:23} | {:9} | {:46} |", mod->first, mod->second->version(), mod->second->description()) << std::endl; + } + s << fmt::format("╰─────────────────────────┴───────────┴────────────────────────────────────────────────╯") << std::endl; + s << "```"; - dpp::channel* c = dpp::find_channel(message.msg.channel_id); - if (c) { - bot->core->message_create(dpp::message(c->id, s.str())); - - } - - } else if (lowercase(subcommand) == "load") { + dpp::channel *c = dpp::find_channel(message.msg.channel_id); + if (c) + { + bot->core->message_create(dpp::message(c->id, s.str())); + } + } + else if (lowercase(subcommand) == "load") + { std::string modfile; tokens >> modfile; - if (bot->loader->load(modfile)) { + if (bot->loader->load(modfile)) + { EmbedSimple("Loaded module: " + modfile, message.msg.channel_id); - } else { + } + else + { EmbedSimple(std::string("Can't do that, check server logs"), message.msg.channel_id); } - } else if (lowercase(subcommand) == "unload") { + } + else if (lowercase(subcommand) == "unload") + { std::string modfile; tokens >> modfile; - if (modfile == "module_mmanager.so") { + if (modfile == "module_mmanager.so") + { EmbedSimple("That's the module manager, are you sure about that chief?", message.msg.channel_id); } - if (bot->loader->unload(modfile)) { + if (bot->loader->unload(modfile)) + { EmbedSimple("Unloaded module: " + modfile, message.msg.channel_id); - } else { + } + else + { EmbedSimple("Can't do that, check server logs.", message.msg.channel_id); } - } else if(lowercase(subcommand) == "reload") { + } + else if (lowercase(subcommand) == "reload") + { std::string modfile; tokens >> modfile; - if (modfile == "module_mmanager.so") { + if (modfile == "module_mmanager.so") + { EmbedSimple("That's the module manager, are you sure about that chief?", message.msg.channel_id); ::sleep(500); } - if (bot->loader->reload(modfile)) { + if (bot->loader->reload(modfile)) + { EmbedSimple("Reloaded module: " + modfile, message.msg.channel_id); - } else { + } + else + { EmbedSimple("Can't do that, check server logs", message.msg.channel_id); } - } else if (lowercase(subcommand) == "ping") { - dpp::channel* c = dpp::find_channel(message.msg.channel_id); - if (c) { - std::chrono::steady_clock::time_point start_time = std::chrono::steady_clock::now(); - dpp::snowflake cid = message.msg.channel_id; - bot->core->message_create(dpp::message(message.msg.channel_id, "Pinging..."), [cid, this, start_time](const dpp::confirmation_callback_t & state) { + } + else if (lowercase(subcommand) == "ping") + { + dpp::channel *c = dpp::find_channel(message.msg.channel_id); + if (c) + { + std::chrono::steady_clock::time_point start_time = std::chrono::steady_clock::now(); + dpp::snowflake cid = message.msg.channel_id; + bot->core->message_create(dpp::message(message.msg.channel_id, "Pinging..."), [cid, this, start_time](const dpp::confirmation_callback_t &state) + { double microseconds_ping = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - start_time).count(); dpp::snowflake mid = (std::get<dpp::message>(state.value)).id; this->bot->core->message_delete(mid, cid); - this->EmbedSimple(fmt::format("**Pong!** REST Response time: {:.3f} ms", microseconds_ping / 1000, 4), cid); - }); - } - } else if (lowercase(subcommand) == "restart") { + this->EmbedSimple(fmt::format("**Pong!** REST Response time: {:.3f} ms", microseconds_ping / 1000, 4), cid); }); + } + } + else if (lowercase(subcommand) == "restart") + { EmbedSimple("Restarting...", message.msg.channel_id); ::sleep(5); exit(0); - } else { - EmbedSimple("Command not found.", message.msg.channel_id); - } - } else { + } + else if (lowercase(subcommand) == "sql") + { + std::string sql; + std::getline(tokens, sql); + sql = trim(sql); + // Create transaction + pqxx::work tx(bot->conn); + + auto res = tx.exec(sql); + std::stringstream w; + dpp::message msg = message.msg; + if (res.affected_rows() == 0) + { + { + EmbedSimple("Successfully executed, no rows returned.", msg.channel_id); + } + } + else + { + auto rs = res.iter(); + w << "- " << sql << std::endl; + auto check = rs.begin(); + w << "+ Rows Returned: " << res.size() << std::endl; + for (auto name = rs.begin(); name != rs.end(); ++name) + { + if (name == rs.begin()) + { + w << " ╭"; + } + w << "────────────────────"; + check = name; + w << (++check != rs.end() ? "┬" : "╮\n"); + } + w << " "; + for (auto name = rs.begin(); name != rs.end(); ++name) + { + // w << fmt::format("│{:20}", name); + } + w << "│" << std::endl; + for (auto name = rs.begin(); name != rs.end(); ++name) + { + if (name == rs.begin()) + { + w << " ├"; + } + w << "────────────────────"; + check = name; + w << (++check != rs.end() ? "┼" : "┤\n"); + } + for (auto row : res) + { + if (w.str().length() < 1900) + { + w << " "; + for (auto field : row) + { + w << fmt::format("│{:20}", field.as<std::string>().substr(0, 20)); + } + w << "│" << std::endl; + } + } + for (auto name = rs.begin(); name != rs.end(); ++name) + { + if (name == rs.begin()) + { + w << " ╰"; + } + w << "────────────────────"; + check = name; + w << (++check != rs.end() ? "┴" : "╯\n"); + } + dpp::channel *c = dpp::find_channel(msg.channel_id); + if (c) + { + bot->core->message_create(dpp::message(msg.channel_id, "```diff\n" + w.str() + "```")); + } + } + } + else + { + EmbedSimple("Command not found.", message.msg.channel_id); + } + } + else + { bot->core->log(dpp::ll_error, fmt::format("Called ModuleManager as a mortal ({})", bot->get_owner_id())); message.reply(dpp::message("nope")); } - } + } return true; } diff --git a/modules/reactions/reactions.cpp b/modules/reactions/reactions.cpp index 6455840..3f698b0 100644 --- a/modules/reactions/reactions.cpp +++ b/modules/reactions/reactions.cpp @@ -4,6 +4,7 @@ #include <142bot/modules.hpp> #include <142bot/util.hpp> #include <fmt/format.h> +#include <sentry.h> using std::to_string; class ReactionsModule : public Module { @@ -12,6 +13,9 @@ public: ReactionsModule(Bot* creator, ModuleLoader* ml): Module(creator, ml) { ml->attach({I_OnMessage}, this); + sentry_value_t crumb = sentry_value_new_breadcrumb("default", "Loaded module reactions"); + sentry_add_breadcrumb(crumb); + std::ifstream f("resources/reactions.json"); json reactions = json::parse(f); @@ -28,6 +32,7 @@ public: return "Auto-reactions based on keyword"; } virtual bool OnMessage(const dpp::message_create_t &message, const std::string& clean_message, bool mentioned, const std::vector<std::string> &stringmentions) { + sentry_set_tag("module", "reactions"); for (auto i = reactionMap.begin(); i != reactionMap.end(); i++) { if (lowercase(clean_message).find(i->first) != std::string::npos) { bot->core->message_add_reaction(message.msg, i->second); diff --git a/modules/spotify/spotify.cpp b/modules/spotify/spotify.cpp index df7515d..aca0f85 100644 --- a/modules/spotify/spotify.cpp +++ b/modules/spotify/spotify.cpp @@ -39,6 +39,7 @@ public: } virtual bool OnMessage(const dpp::message_create_t &message, const std::string& clean_message, bool mentioned, const std::vector<std::string> & mentions) { + sentry_set_tag("module", "spotify"); bot->core->log(dpp::ll_debug, "Got message event"); const char* pcre_error; diff --git a/src/bot.cpp b/src/bot.cpp index ad818a0..d0f6377 100644 --- a/src/bot.cpp +++ b/src/bot.cpp @@ -1,4 +1,5 @@ +#include "sentry.h" #include <dpp/snowflake.h> #include <stdlib.h> #include <string> @@ -37,7 +38,8 @@ Bot::Bot(bool devel, dpp::cluster* cluster) { * Returns false on any error */ bool Bot::run_database_migrations() { - + sentry_value_t crumb = sentry_value_new_breadcrumb("debug", "Running database migrations"); + sentry_value_set_by_key(crumb, "level", sentry_value_new_string("debug")); // Start a transaction this->core->log(dpp::ll_info, "Attempting database migrations..."); pqxx::work w(this->conn); @@ -24,6 +24,7 @@ #include <pqxx/pqxx> #include <fmt/format.h> #include <cstdarg> +#include <sentry.h> using namespace std; @@ -36,6 +37,7 @@ namespace db { **/ pqxx::connection connect(const std::string &host, const std::string &user, const std::string &pass, const std::string &db, int port) { std::lock_guard<std::mutex> db_lock(db_mutex); + std::string cn_s = "postgresql://"; @@ -60,6 +62,11 @@ namespace db { cn_s = cn_s + "/" + db; } + sentry_value_t crumb = sentry_value_new_breadcrumb("default", "Started Database Connection"); + sentry_value_set_by_key(crumb, "level", sentry_value_new_string("db")); + sentry_value_set_by_key(crumb, "data", sentry_value_new_string(cn_s.c_str())); + sentry_add_breadcrumb(crumb); + try { pqxx::connection c{cn_s}; return c; diff --git a/src/main.cpp b/src/main.cpp index f54e418..db79289 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -9,15 +9,31 @@ #include <spdlog/sinks/rotating_file_sink.h> #include <string> +#include <sentry.h> + +#include "142bot_config.h" + using namespace std; using json = nlohmann::json; + + int main(int argc, char const *argv[]) { std::ifstream f("config.json"); json cfg = json::parse(f); string token = cfg.value("token", "bad-token"); + sentry_options_t *options = sentry_options_new(); + sentry_options_set_dsn(options, "https://26f71a6064ee478c8d944b976b89eb3c@o4504969688317952.ingest.sentry.io/4504969689563136"); + // This is also the default-path. For further information and recommendations: + // https://docs.sentry.io/platforms/native/configuration/options/#database-path + sentry_options_set_database_path(options, ".sentry-native"); + sentry_options_set_release(options, "142bot@" + onefortytwobot_VERSION_MAJOR + '.' + onefortytwobot_VERSION_MINOR); + sentry_options_set_debug(options, 0); + sentry_options_set_environment(options, onefortytwobot_env); + sentry_options_set_symbolize_stacktraces(options, 1); + sentry_init(options); dpp::cluster bot(token, dpp::intents::i_all_intents); std::shared_ptr<spdlog::logger> log; @@ -68,5 +84,6 @@ int main(int argc, char const *argv[]) { bot.on_message_reaction_add(std::bind(&Bot::onMessageReactionAdd, &client, std::placeholders::_1)); bot.start(dpp::st_wait); + sentry_close(); return 0; } |