aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCara Salter <cara@devcara.com>2023-04-06 21:43:29 -0400
committerCara Salter <cara@devcara.com>2023-04-06 21:43:29 -0400
commitacd1befde66db492149992199fadca92e55cc97b (patch)
tree16251d96cd8efd5323fa8f095bb29f110030f387
parent555810bedc0cf9d9d954f56b5a2c8c92522ad27f (diff)
download142bot-acd1befde66db492149992199fadca92e55cc97b.tar.gz
142bot-acd1befde66db492149992199fadca92e55cc97b.zip
sentry: Add sentry support
Change-Id: I3cff2a05c63e88abddc8eff6a3ee9a9f73a5172d
-rw-r--r--142bot.config.in6
-rw-r--r--CMakeLists.txt18
-rw-r--r--include/142bot/bot.hpp2
-rw-r--r--include/142bot/modules.hpp7
-rw-r--r--modules/mmanager/mmanager.cpp250
-rw-r--r--modules/reactions/reactions.cpp5
-rw-r--r--modules/spotify/spotify.cpp1
-rw-r--r--src/bot.cpp4
-rw-r--r--src/db.cpp7
-rw-r--r--src/main.cpp17
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);
diff --git a/src/db.cpp b/src/db.cpp
index 92e3d1d..cea15c0 100644
--- a/src/db.cpp
+++ b/src/db.cpp
@@ -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;
}