aboutsummaryrefslogtreecommitdiff
path: root/src/modules.cpp
diff options
context:
space:
mode:
authorCara Salter <cara@devcara.com>2023-03-30 12:52:19 -0400
committerCara Salter <cara@devcara.com>2023-03-30 12:52:19 -0400
commit527b7ab2df126bb2f480999049ed05b057a6ef83 (patch)
tree8edb7c72d7fae0e7d2c768f5f5dd65c2268c75a0 /src/modules.cpp
parentc8befe7c95b18869f995c4f2cbc2f4cf9c91924f (diff)
download142bot-527b7ab2df126bb2f480999049ed05b057a6ef83.tar.gz
142bot-527b7ab2df126bb2f480999049ed05b057a6ef83.zip
modules!
Diffstat (limited to 'src/modules.cpp')
-rw-r--r--src/modules.cpp412
1 files changed, 412 insertions, 0 deletions
diff --git a/src/modules.cpp b/src/modules.cpp
new file mode 100644
index 0000000..efdc447
--- /dev/null
+++ b/src/modules.cpp
@@ -0,0 +1,412 @@
+#include <dlfcn.h>
+#include <dpp/dpp.h>
+
+#include <142bot/modules.hpp>
+#include <fmt/format.h>
+#include <mutex>
+#include <limits.h>
+#include <link.h>
+
+const char* StringNames[I_END + 1] = {
+ "I_BEGIN",
+ "I_OnMessage",
+ "I_OnReady",
+ "I_OnChannelCreate",
+ "I_OnChannelDelete",
+ "I_OnGuildMemberAdd",
+ "I_OnGuildCreate",
+ "I_OnGuildDelete",
+ "I_OnPresenceUpdate",
+ "I_OnRestEnd",
+ "I_OnAllShardsReady",
+ "I_OnTypingStart",
+ "I_OnMessageUpdate",
+ "I_OnMessageDelete",
+ "I_OnMessageDeleteBulk",
+ "I_OnGuildUpdate",
+ "I_OnMessageReactionAdd",
+ "I_OnMessageReactionRemove",
+ "I_OnMessageReactionRemoveAll",
+ "I_OnUserUpdate",
+ "I_OnResumed",
+ "I_OnChannelUpdate",
+ "I_OnChannelPinsUpdate",
+ "I_OnGuildBanAdd",
+ "I_OnGuildBanRemove",
+ "I_OnGuildEmojisUpdate",
+ "I_OnGuildIntegrationsUpdate",
+ "I_OnGuildMemberRemove",
+ "I_OnGuildMemberUpdate",
+ "I_OnGuildMembersChunk",
+ "I_OnGuildRoleCreate",
+ "I_OnGuildRoleUpdate",
+ "I_OnGuildRoleDelete",
+ "I_OnPresenceUpdateWS",
+ "I_OnVoiceStateUpdate",
+ "I_OnVoiceServerUpdate",
+ "I_OnWebhooksUpdate",
+ "I_END"
+};
+
+
+ModuleLoader::ModuleLoader(Bot* creator): bot(creator) {
+ bot->core->log(dpp::ll_info, "Module loader init");
+}
+
+// Attach a module to an event dynamically
+void ModuleLoader::attach(const std::vector<Events> &i, Module* m) {
+ for (auto n = i.begin(); n != i.end(); ++n) {
+ if (std::find(EventHandlers[*n].begin(), EventHandlers[*n].end(), m) == EventHandlers[*n].end()) {
+ EventHandlers[*n].push_back(m);
+ bot->core->log(dpp::ll_info, fmt::format("Module {} attached to event {}", m->description(), StringNames[*n]));
+ } else {
+ bot->core->log(dpp::ll_warning, fmt::format("Module {} already attached to event {}", m->description(), StringNames[*n]));
+ }
+ }
+}
+
+// Detach a module from an event
+void ModuleLoader::detach(const std::vector<Events> &e, Module *m) {
+ for (auto n = e.begin(); n != e.end(); ++n) {
+ auto it = std::find(EventHandlers[*n].begin(), EventHandlers[*n].end(), m);
+ if (it != EventHandlers[*n].end()) {
+ EventHandlers[*n].erase(it);
+ bot->core->log(dpp::ll_info, fmt::format("Module {} detached from event {}", m->description(), StringNames[*n]));
+ }
+ }
+}
+
+// Get Loaded module list
+const ModuleMap& ModuleLoader::get_loaded_modules() const {
+ return this->mod_map;
+}
+
+// Load a new module
+bool ModuleLoader::load(const std::string &fname) {
+
+ ModuleLowLevel m;
+ m.dlopen_handle = nullptr;
+ m.init = nullptr;
+ m.mod = nullptr;
+
+ bot->core->log(dpp::ll_info, fmt::format("Attempting to load module {}", fname));
+
+ std::lock_guard l(this->mtx);
+
+ if (Modules.find(fname) == Modules.end()) {
+ char buffer[PATH_MAX + 1];
+ getcwd(buffer, PATH_MAX);
+ std::string full_path = std::string(buffer) + "/" + fname;
+
+ m.dlopen_handle = dlopen(full_path.c_str(), RTLD_NOW | RTLD_LOCAL);
+ if (!m.dlopen_handle) {
+ bot->core->log(dpp::ll_error, fmt::format("Can't load module: {}", dlerror()));
+ return false;
+ } else {
+ if (!get_symbol(m, "init_module")) {
+ bot->core->log(dpp::ll_error, fmt::format("Could not find init_module symbol"));
+ dlclose(m.dlopen_handle);
+ return false;
+ } else {
+ bot->core->log(dpp::ll_debug, "Symbol found, attempting to load module");
+ m.mod = m.init(bot, this);
+
+ if (!m.mod || (uint64_t)m.mod == 0xffffffffffffffff) {
+ bot->core->log(dpp::ll_error, "Invalid module pointer returned");
+ dlclose(m.dlopen_handle);
+ return false;
+ } else {
+ bot->core->log(dpp::ll_info, fmt::format("Loaded module {}", m.mod->description()));
+ Modules[fname] = m;
+ mod_map[fname] = m.mod;
+ return true;
+ }
+ }
+ }
+ } else {
+ bot->core->log(dpp::ll_error, "Module already loaded");
+ return false;
+ }
+ return true;
+}
+
+// Unloads a module
+bool ModuleLoader::unload(const std::string &fname) {
+ std::lock_guard l(mtx);
+
+ auto m = Modules.find(fname);
+
+ if (m == Modules.end()) {
+ bot->core->log(dpp::ll_error, "Module not loaded");
+ return false;
+ }
+
+ ModuleLowLevel& mod = m->second;
+
+ // Remove attached events
+ for (int j = I_BEGIN; j != I_END; ++j) {
+ auto p = std::find(EventHandlers[j].begin(), EventHandlers[j].end(), mod.mod);
+ if (p != EventHandlers[j].end()) {
+ EventHandlers[j].erase(p);
+ bot->core->log(dpp::ll_debug, fmt::format("Removed event {} from {}", StringNames[j], fname));
+ }
+ }
+
+ Modules.erase(m);
+
+ auto v = mod_map.find(fname);
+ if (v != mod_map.end()) {
+ mod_map.erase(v);
+ bot->core->log(dpp::ll_debug, "Removed module from public list");
+ }
+
+ if (mod.mod) {
+ delete mod.mod;
+ }
+
+ if (mod.dlopen_handle) {
+ dlclose(mod.dlopen_handle);
+ bot->core->log(dpp::ll_debug, "Unloaded module");
+ }
+
+ return true;
+
+}
+
+/**
+ * Return a given symbol name from a shared object represented by the ModuleNative value.
+ */
+bool ModuleLoader::get_symbol(ModuleLowLevel &native, const char *sym_name)
+{
+ /* Find exported symbol in shared object */
+ if (native.dlopen_handle) {
+ dlerror(); // clear value
+ native.init = (initfunctype*)dlsym(native.dlopen_handle, sym_name);
+ //printf("dlopen_handle=0x%016x, native.init=0x%016x native.err=\"%s\" dlsym=0x%016x sym_name=%s\n", native.dlopen_handle, native.init, native.err ? native.err : "<NULL>", dlsym(native.dlopen_handle, sym_name), sym_name);
+
+ } else {
+ bot->core->log(dpp::ll_error, "ModuleLoader::GetSymbol(): Invalid dlopen() handle");
+ return false;
+ }
+ return true;
+}
+
+Module::Module(Bot* instigator, ModuleLoader* ml) : bot(instigator)
+{
+}
+
+Module::~Module()
+{
+}
+
+std::string Module::version()
+{
+ return "";
+}
+
+std::string Module::description()
+{
+ return "";
+}
+
+bool Module::OnChannelCreate(const dpp::channel_create_t &channel)
+{
+ return true;
+}
+
+bool Module::OnReady(const dpp::ready_t &ready)
+{
+ return true;
+}
+
+bool Module::OnChannelDelete(const dpp::channel_delete_t &channel)
+{
+ return true;
+}
+
+bool Module::OnGuildCreate(const dpp::guild_create_t &guild)
+{
+ return true;
+}
+
+bool Module::OnGuildDelete(const dpp::guild_delete_t &guild)
+{
+ return true;
+}
+
+bool Module::OnGuildMemberAdd(const dpp::guild_member_add_t &gma)
+{
+ return true;
+}
+
+bool Module::OnMessage(const dpp::message_create_t &message, const std::string& clean_message, bool mentioned, const std::vector<std::string> &stringmentions)
+{
+ return true;
+}
+
+bool Module::OnPresenceUpdate()
+{
+ return true;
+}
+
+bool Module::OnTypingStart(const dpp::typing_start_t &obj)
+{
+ return true;
+}
+
+
+bool Module::OnMessageUpdate(const dpp::message_update_t &obj)
+{
+ return true;
+}
+
+
+bool Module::OnMessageDelete(const dpp::message_delete_t &obj)
+{
+ return true;
+}
+
+
+bool Module::OnMessageDeleteBulk(const dpp::message_delete_bulk_t &obj)
+{
+ return true;
+}
+
+
+bool Module::OnGuildUpdate(const dpp::guild_update_t &obj)
+{
+ return true;
+}
+
+
+bool Module::OnMessageReactionAdd(const dpp::message_reaction_add_t &obj)
+{
+ return true;
+}
+
+
+bool Module::OnMessageReactionRemove(const dpp::message_reaction_remove_t &obj)
+{
+ return true;
+}
+
+
+bool Module::OnMessageReactionRemoveAll(const dpp::message_reaction_remove_all_t &obj)
+{
+ return true;
+}
+
+
+bool Module::OnUserUpdate(const dpp::user_update_t &obj)
+{
+ return true;
+}
+
+
+bool Module::OnResumed(const dpp::resumed_t &obj)
+{
+ return true;
+}
+
+
+bool Module::OnChannelUpdate(const dpp::channel_update_t &obj)
+{
+ return true;
+}
+
+
+bool Module::OnChannelPinsUpdate(const dpp::channel_pins_update_t &obj)
+{
+ return true;
+}
+
+
+bool Module::OnGuildBanAdd(const dpp::guild_ban_add_t &obj)
+{
+ return true;
+}
+
+
+bool Module::OnGuildBanRemove(const dpp::guild_ban_remove_t &obj)
+{
+ return true;
+}
+
+
+bool Module::OnGuildEmojisUpdate(const dpp::guild_emojis_update_t &obj)
+{
+ return true;
+}
+
+
+bool Module::OnGuildIntegrationsUpdate(const dpp::guild_integrations_update_t &obj)
+{
+ return true;
+}
+
+
+bool Module::OnGuildMemberRemove(const dpp::guild_member_remove_t &obj)
+{
+ return true;
+}
+
+
+bool Module::OnGuildMemberUpdate(const dpp::guild_member_update_t &obj)
+{
+ return true;
+}
+
+
+bool Module::OnGuildMembersChunk(const dpp::guild_members_chunk_t &obj)
+{
+ return true;
+}
+
+
+bool Module::OnGuildRoleCreate(const dpp::guild_role_create_t &obj)
+{
+ return true;
+}
+
+
+bool Module::OnGuildRoleUpdate(const dpp::guild_role_update_t &obj)
+{
+ return true;
+}
+
+
+bool Module::OnGuildRoleDelete(const dpp::guild_role_delete_t &obj)
+{
+ return true;
+}
+
+
+bool Module::OnPresenceUpdateWS(const dpp::presence_update_t &obj)
+{
+ return true;
+}
+
+
+bool Module::OnVoiceStateUpdate(const dpp::voice_state_update_t &obj)
+{
+ return true;
+}
+
+
+bool Module::OnVoiceServerUpdate(const dpp::voice_server_update_t &obj)
+{
+ return true;
+}
+
+
+bool Module::OnWebhooksUpdate(const dpp::webhooks_update_t &obj)
+{
+ return true;
+}
+
+bool Module::OnAllShardsReady()
+{
+ return true;
+}
+
+