aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--CMakeLists.txt4
-rw-r--r--cmake/FindPCRE.cmake37
-rw-r--r--include/142bot/bot.hpp5
-rw-r--r--include/142bot/modules.hpp3
-rw-r--r--modules/mmanager/mmanager.cpp107
-rw-r--r--modules/reactions/reactions.cpp43
-rw-r--r--resources/reactions.json3
-rw-r--r--src/bot.cpp14
-rw-r--r--src/main.cpp6
-rw-r--r--src/meta.cpp9
-rw-r--r--src/modules.cpp39
12 files changed, 254 insertions, 19 deletions
diff --git a/.gitignore b/.gitignore
index c9a6733..74a777d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -95,4 +95,5 @@ tags
# End of https://www.toptal.com/developers/gitignore/api/cmake,c++,visualstudiocode,vim
build/
-config.json \ No newline at end of file
+config.json
+.cache/
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1b2e67c..40edb5e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -16,6 +16,8 @@ FetchContent_Declare(dpp
FetchContent_MakeAvailable(clog dpp)
+include(cmake/FindPCRE.cmake)
+
find_package(fmt)
string(ASCII 27 Esc)
@@ -24,7 +26,7 @@ aux_source_directory("src" coresrc)
add_executable(142bot ${coresrc})
include_directories("include")
-target_link_libraries(142bot clog dpp fmt spdlog)
+target_link_libraries(142bot clog dpp fmt spdlog pcre)
set (modules_dir "modules")
file(GLOB subdirlist ${modules_dir}/*)
diff --git a/cmake/FindPCRE.cmake b/cmake/FindPCRE.cmake
new file mode 100644
index 0000000..d6a77a5
--- /dev/null
+++ b/cmake/FindPCRE.cmake
@@ -0,0 +1,37 @@
+# Copyright (C) 2007-2009 LuaDist.
+# Created by Peter Kapec <kapecp@gmail.com>
+# Redistribution and use of this file is allowed according to the terms of the MIT license.
+# For details see the COPYRIGHT file distributed with LuaDist.
+# Note:
+# Searching headers and libraries is very simple and is NOT as powerful as scripts
+# distributed with CMake, because LuaDist defines directories to search for.
+# Everyone is encouraged to contact the author with improvements. Maybe this file
+# becomes part of CMake distribution sometimes.
+
+# - Find pcre
+# Find the native PCRE headers and libraries.
+#
+# PCRE_INCLUDE_DIRS - where to find pcre.h, etc.
+# PCRE_LIBRARIES - List of libraries when using pcre.
+# PCRE_FOUND - True if pcre found.
+
+# Look for the header file.
+FIND_PATH(PCRE_INCLUDE_DIR NAMES pcre.h)
+
+# Look for the library.
+FIND_LIBRARY(PCRE_LIBRARY NAMES pcre)
+
+# Handle the QUIETLY and REQUIRED arguments and set PCRE_FOUND to TRUE if all listed variables are TRUE.
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(PCRE DEFAULT_MSG PCRE_LIBRARY PCRE_INCLUDE_DIR)
+
+# Copy the results to the output variables.
+IF(PCRE_FOUND)
+ SET(PCRE_LIBRARIES ${PCRE_LIBRARY})
+ SET(PCRE_INCLUDE_DIRS ${PCRE_INCLUDE_DIR})
+ELSE(PCRE_FOUND)
+ SET(PCRE_LIBRARIES)
+ SET(PCRE_INCLUDE_DIRS)
+ENDIF(PCRE_FOUND)
+
+MARK_AS_ADVANCED(PCRE_INCLUDE_DIRS PCRE_LIBRARIES) \ No newline at end of file
diff --git a/include/142bot/bot.hpp b/include/142bot/bot.hpp
index c919179..49aa956 100644
--- a/include/142bot/bot.hpp
+++ b/include/142bot/bot.hpp
@@ -1,3 +1,4 @@
+#include <dpp/snowflake.h>
#include <dpp/user.h>
#include <dpp/dpp.h>
@@ -8,6 +9,7 @@ class Module;
class ModuleLoader;
class Bot {
bool dev;
+ dpp::snowflake owner_id;
public:
class dpp::cluster * core;
@@ -16,6 +18,9 @@ public:
Bot(bool development, dpp::cluster* cluster);
//virtual ~Bot();
+
+ void set_owner_id(dpp::snowflake id);
+ dpp::snowflake get_owner_id();
ModuleLoader* loader;
diff --git a/include/142bot/modules.hpp b/include/142bot/modules.hpp
index d1bb3f6..ab888d3 100644
--- a/include/142bot/modules.hpp
+++ b/include/142bot/modules.hpp
@@ -134,7 +134,7 @@ public:
bool unload(const std::string &fname);
// Unloads and then reloads a module
- void reload(const std::string &fname);
+ bool reload(const std::string &fname);
// Get list of loaded modules
const ModuleMap& get_loaded_modules() const;
@@ -186,6 +186,7 @@ public:
virtual bool OnVoiceStateUpdate(const dpp::voice_state_update_t &obj);
virtual bool OnVoiceServerUpdate(const dpp::voice_server_update_t &obj);
virtual bool OnWebhooksUpdate(const dpp::webhooks_update_t &obj);
+ void EmbedSimple(const std::string &message, int64_t channelID);
};
/* A macro that lets us simply define the entrypoint of a module by name */
diff --git a/modules/mmanager/mmanager.cpp b/modules/mmanager/mmanager.cpp
index fda8b3c..36b6aae 100644
--- a/modules/mmanager/mmanager.cpp
+++ b/modules/mmanager/mmanager.cpp
@@ -19,14 +19,17 @@
#include <stdlib.h>
#include <string>
#include <142bot/modules.hpp>
+#include <142bot/util.hpp>
+#include <pcre.h>
#include <dpp/dpp.h>
+#include <fmt/format.h>
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!");
+ creator->core->log(dpp::ll_info, "ModuleManager online!");
}
virtual std::string version() {
@@ -43,7 +46,107 @@ public:
}
virtual bool OnMessage(const dpp::message_create_t &message, const std::string& clean_message, bool mentioned, const std::vector<std::string> &stringmentions) {
- bot->core->log(dpp::ll_info, "Got message!");
+ 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) {
+ 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) {
+ 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()) {
+ // Tokenize
+ 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));
+
+ 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();
+
+ 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 << "```";
+
+ 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)) {
+ EmbedSimple("Loaded module: " + modfile, message.msg.channel_id);
+ } else {
+ EmbedSimple(std::string("Can't do that, check server logs"), message.msg.channel_id);
+ }
+ } else if (lowercase(subcommand) == "unload") {
+ std::string modfile;
+ tokens >> modfile;
+ 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)) {
+ EmbedSimple("Unloaded module: " + modfile, message.msg.channel_id);
+ } else {
+ EmbedSimple("Can't do that, check server logs.", message.msg.channel_id);
+ }
+ } else if(lowercase(subcommand) == "reload") {
+ std::string modfile;
+ tokens >> modfile;
+ 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)) {
+ EmbedSimple("Reloaded module: " + modfile, message.msg.channel_id);
+ } 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) {
+ 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 {
+ 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
new file mode 100644
index 0000000..3818d0d
--- /dev/null
+++ b/modules/reactions/reactions.cpp
@@ -0,0 +1,43 @@
+#include <dpp/message.h>
+#include <dpp/json.h>
+#include <stdlib.h>
+#include <142bot/modules.hpp>
+#include <fmt/format.h>
+
+using std::to_string;
+class ReactionsModule : public Module {
+ std::map<std::string, std::string> reactionMap;
+public:
+ ReactionsModule(Bot* creator, ModuleLoader* ml): Module(creator, ml) {
+ ml->attach({I_OnMessage}, this);
+
+ std::ifstream f("resources/reactions.json");
+ json reactions = json::parse(f);
+
+ for(auto it = reactions.begin(); it != reactions.end(); it++) {
+ reactionMap.insert_or_assign(it.key(), reactions.value(it.key(), ""));
+ }
+ }
+
+ virtual std::string version() {
+ return "0.1.0";
+ }
+
+ virtual std::string description() {
+ 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) {
+ for (auto i = reactionMap.begin(); i != reactionMap.end(); i++) {
+ if (clean_message.find(i->first) != std::string::npos) {
+ bot->core->message_add_reaction(message.msg, i->second);
+ bot->core->log(dpp::ll_debug, "Adding reaction based on keyword");
+ }
+ }
+
+ return true;
+ }
+
+};
+
+
+ENTRYPOINT(ReactionsModule) \ No newline at end of file
diff --git a/resources/reactions.json b/resources/reactions.json
new file mode 100644
index 0000000..5d4ccaa
--- /dev/null
+++ b/resources/reactions.json
@@ -0,0 +1,3 @@
+{
+ "test": "🔧"
+} \ No newline at end of file
diff --git a/src/bot.cpp b/src/bot.cpp
index 1c764b7..57bf091 100644
--- a/src/bot.cpp
+++ b/src/bot.cpp
@@ -1,4 +1,5 @@
+#include <dpp/snowflake.h>
#include <stdlib.h>
#include <142bot/bot.hpp>
#include <dpp/dpp.h>
@@ -22,6 +23,14 @@ bool Bot::isDevMode() {
return dev;
}
+void Bot::set_owner_id(dpp::snowflake id) {
+ this->owner_id = id;
+}
+
+dpp::snowflake Bot::get_owner_id() {
+ return this->owner_id;
+}
+
int64_t Bot::getID() {
return this->user.id;
}
@@ -127,9 +136,8 @@ void Bot::onGuildUpdate(const dpp::guild_update_t &obj)
}
-void Bot::onMessageReactionAdd(const dpp::message_reaction_add_t &obj)
-{
-
+void Bot::onMessageReactionAdd(const dpp::message_reaction_add_t &obj) {
+ FOREACH_MOD(I_OnMessageReactionAdd, OnMessageReactionAdd(obj));
}
diff --git a/src/main.cpp b/src/main.cpp
index d58f474..8f3ad9a 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -6,6 +6,7 @@
#include <spdlog/async.h>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/sinks/rotating_file_sink.h>
+#include <string>
using namespace std;
@@ -29,7 +30,7 @@ int main(int argc, char const *argv[]) {
log = std::make_shared<spdlog::async_logger>("logs", sinks.begin(), sinks.end(), spdlog::thread_pool(), spdlog::async_overflow_policy::block);
spdlog::register_logger(log);
log->set_pattern("%^%Y-%m-%d %H:%M:%S.%e [%L] [th#%t]%$ : %v");
- log->set_level(spdlog::level::level_enum::debug);
+ log->set_level(spdlog::level::level_enum::trace);
/* Integrate spdlog logger to D++ log events */
bot.on_log([&bot, &log](const dpp::log_t & event) {
@@ -59,9 +60,12 @@ int main(int argc, char const *argv[]) {
Bot client(0, &bot);
+ client.set_owner_id(dpp::snowflake(cfg.value("owner", "00000000000")));
+
/* Attach events to the Bot class methods */
bot.on_message_create(std::bind(&Bot::onMessage, &client, std::placeholders::_1));
bot.on_ready(std::bind(&Bot::onReady, &client, std::placeholders::_1));
+ bot.on_message_reaction_add(std::bind(&Bot::onMessageReactionAdd, &client, std::placeholders::_1));
bot.start(dpp::st_wait);
return 0;
diff --git a/src/meta.cpp b/src/meta.cpp
deleted file mode 100644
index 3ae58a7..0000000
--- a/src/meta.cpp
+++ /dev/null
@@ -1,9 +0,0 @@
-#include <dpp/dpp.h>
-#include <commandhandler.h>
-
-using namespace std;
-using namespace dpp;
-
-void about(const std::string &name, const parameter_list_t &params, command_source) {
-
-} \ No newline at end of file
diff --git a/src/modules.cpp b/src/modules.cpp
index efdc447..6a8d500 100644
--- a/src/modules.cpp
+++ b/src/modules.cpp
@@ -116,7 +116,7 @@ bool ModuleLoader::load(const std::string &fname) {
dlclose(m.dlopen_handle);
return false;
} else {
- bot->core->log(dpp::ll_info, fmt::format("Loaded module {}", m.mod->description()));
+ bot->core->log(dpp::ll_info, fmt::format("Loaded {} ({})", m.mod->description(), m.mod->version()));
Modules[fname] = m;
mod_map[fname] = m.mod;
return true;
@@ -173,6 +173,15 @@ bool ModuleLoader::unload(const std::string &fname) {
}
+
+bool ModuleLoader::reload(const std::string &filename)
+{
+ /* Short-circuit evaluation here means that if Unload() returns false,
+ * Load() won't be called at all.
+ */
+ return (unload(filename) && load(filename));
+}
+
/**
* Return a given symbol name from a shared object represented by the ModuleNative value.
*/
@@ -410,3 +419,31 @@ bool Module::OnAllShardsReady()
}
+
+/**
+ * Output a simple embed to a channel consisting just of a message.
+ */
+void Module::EmbedSimple(const std::string &message, int64_t channelID)
+{
+ std::stringstream s;
+ json embed_json;
+
+ s << "{\"color\":16767488, \"description\": \"" << message << "\"}";
+
+ try {
+ embed_json = json::parse(s.str());
+ }
+ catch (const std::exception &e) {
+ bot->core->log(dpp::ll_error, fmt::format("Invalid json for channel {} created by EmbedSimple: ", channelID, s.str()));
+ }
+ dpp::channel* channel = dpp::find_channel(channelID);
+ if (channel) {
+ dpp::message m;
+ m.channel_id = channel->id;
+ m.embeds.push_back(dpp::embed(&embed_json));
+ bot->core->message_create(m);
+
+ } else {
+ bot->core->log(dpp::ll_error, fmt::format("Invalid channel {} passed to EmbedSimple", channelID));
+ }
+} \ No newline at end of file