aboutsummaryrefslogtreecommitdiff
path: root/include
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 /include
parentc8befe7c95b18869f995c4f2cbc2f4cf9c91924f (diff)
download142bot-527b7ab2df126bb2f480999049ed05b057a6ef83.tar.gz
142bot-527b7ab2df126bb2f480999049ed05b057a6ef83.zip
modules!
Diffstat (limited to 'include')
-rw-r--r--include/142bot/bot.hpp61
-rw-r--r--include/142bot/modules.hpp192
-rw-r--r--include/142bot/util.hpp85
3 files changed, 338 insertions, 0 deletions
diff --git a/include/142bot/bot.hpp b/include/142bot/bot.hpp
new file mode 100644
index 0000000..c919179
--- /dev/null
+++ b/include/142bot/bot.hpp
@@ -0,0 +1,61 @@
+#include <dpp/user.h>
+#include <dpp/dpp.h>
+
+
+#ifndef BOT_HPP
+#define BOT_HPP
+class Module;
+class ModuleLoader;
+class Bot {
+ bool dev;
+
+public:
+ class dpp::cluster * core;
+ /* The bot's user from the ready event */
+ dpp::user user;
+
+ Bot(bool development, dpp::cluster* cluster);
+ //virtual ~Bot();
+
+ ModuleLoader* loader;
+
+ bool isDevMode();
+
+ int64_t getID();
+
+ void onReady(const dpp::ready_t &ready);
+ void onServer(const dpp::guild_create_t &gc);
+ void onMember(const dpp::guild_member_add_t &gma);
+ void onChannel(const dpp::channel_create_t &channel);
+ void onMessage(const dpp::message_create_t &message);
+ void onChannelDelete(const dpp::channel_delete_t &cd);
+ void onServerDelete(const dpp::guild_delete_t &gd);
+ void onTypingStart (const dpp::typing_start_t &event);
+ void onMessageUpdate (const dpp::message_update_t &event);
+ void onMessageDelete (const dpp::message_delete_t &event);
+ void onMessageDeleteBulk (const dpp::message_delete_bulk_t &event);
+ void onGuildUpdate (const dpp::guild_update_t &event);
+ void onMessageReactionAdd (const dpp::message_reaction_add_t &event);
+ void onMessageReactionRemove (const dpp::message_reaction_remove_t &event);
+ void onMessageReactionRemoveAll (const dpp::message_reaction_remove_all_t &event);
+ void onUserUpdate (const dpp::user_update_t &event);
+ void onResumed (const dpp::resumed_t &event);
+ void onChannelUpdate (const dpp::channel_update_t &event);
+ void onChannelPinsUpdate (const dpp::channel_pins_update_t &event);
+ void onGuildBanAdd (const dpp::guild_ban_add_t &event);
+ void onGuildBanRemove (const dpp::guild_ban_remove_t &event);
+ void onGuildEmojisUpdate (const dpp::guild_emojis_update_t &event);
+ void onGuildIntegrationsUpdate (const dpp::guild_integrations_update_t &event);
+ void onGuildMemberRemove (const dpp::guild_member_remove_t &event);
+ void onGuildMemberUpdate (const dpp::guild_member_update_t &event);
+ void onGuildMembersChunk (const dpp::guild_members_chunk_t &event);
+ void onGuildRoleCreate (const dpp::guild_role_create_t &event);
+ void onGuildRoleUpdate (const dpp::guild_role_update_t &event);
+ void onGuildRoleDelete (const dpp::guild_role_delete_t &event);
+ void onPresenceUpdate (const dpp::presence_update_t &event);
+ void onVoiceStateUpdate (const dpp::voice_state_update_t &event);
+ void onVoiceServerUpdate (const dpp::voice_server_update_t &event);
+ void onWebhooksUpdate (const dpp::webhooks_update_t &event);
+};
+
+#endif
diff --git a/include/142bot/modules.hpp b/include/142bot/modules.hpp
new file mode 100644
index 0000000..d1bb3f6
--- /dev/null
+++ b/include/142bot/modules.hpp
@@ -0,0 +1,192 @@
+
+/**
+ * Thinking about modules --
+ *
+ * Essentially what we're doing is loading a .so file at runtime. That then gets turned into everyone's favorite, modules!
+*/
+
+#pragma once
+
+#include "bot.hpp"
+class ModuleLoader;
+class Module;
+
+/**
+ * Enum of possible events to be attached to
+*/
+enum Events
+{
+ 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
+};
+
+/**
+ * This #define allows us to call a method in all loaded modules in a readable simple way, e.g.:
+ * 'FOREACH_MOD(I_OnGuildAdd,OnGuildAdd(guildinfo));'
+ * NOTE: Locks mutex - two FOREACH_MOD() can't run asyncronously in two different threads. This is
+ * to prevent one thread loading/unloading a module, changing the arrays/vectors while another thread
+ * is running an event.
+ */
+#define FOREACH_MOD(y,x) { \
+ std::vector<Module*> list_to_call; \
+ { \
+ std::lock_guard l(loader->mtx); \
+ list_to_call = loader->EventHandlers[y]; \
+ } \
+ for (auto _i = list_to_call.begin(); _i != list_to_call.end(); ++_i) \
+ { \
+ try \
+ { \
+ if (!(*_i)->x) { \
+ break; \
+ } \
+ } \
+ catch (std::exception& modexcept) \
+ { \
+ core->log(dpp::ll_error, fmt::format("Exception caught in module: {}", modexcept.what())); \
+ } \
+ } \
+};
+
+// Module entry function type
+typedef Module* (initfunctype) (Bot*, ModuleLoader*);
+
+// Represents a mapping of module names to modules
+typedef std::map<std::string, Module*> ModuleMap;
+
+// Contains the low-level stuff that goes into a module:
+struct ModuleLowLevel {
+ initfunctype* init;
+ void* dlopen_handle;
+ Module* mod;
+};
+
+/**
+ * The dynamic loader class. Contains details on loaded modules and knows how to load and unload them
+*/
+class ModuleLoader {
+ Bot* bot;
+
+ // Loaded module list
+ std::map<std::string, ModuleLowLevel> Modules;
+
+ // Gets a named symbol from the module
+ bool get_symbol(ModuleLowLevel &lowlevel, const char* name);
+
+ // Externally-provided module map
+ ModuleMap mod_map;
+
+public:
+ // Module mutex
+ std::mutex mtx;
+
+ // List of registered event handlers
+ std::vector<Module*> EventHandlers[I_END];
+
+ ModuleLoader(Bot* creator);
+
+ // Attach a module to an event
+ void attach(const std::vector<Events> &e, Module* m);
+
+ // Detach a module from an event
+ void detach(const std::vector<Events> &e, Module* m);
+
+ // Load a module
+ bool load(const std::string &fname);
+
+ // Unload a module
+ bool unload(const std::string &fname);
+
+ // Unloads and then reloads a module
+ void reload(const std::string &fname);
+
+ // Get list of loaded modules
+ const ModuleMap& get_loaded_modules() const;
+};
+
+// Defines an individual module
+class Module {
+protected:
+ Bot* bot;
+public:
+ Module(Bot* caller, ModuleLoader* ml);
+ virtual ~Module();
+
+ virtual std::string version();
+ virtual std::string description();
+
+ virtual bool OnChannelCreate(const dpp::channel_create_t &channel);
+ virtual bool OnReady(const dpp::ready_t &ready);
+ virtual bool OnChannelDelete(const dpp::channel_delete_t &channel);
+ virtual bool OnGuildCreate(const dpp::guild_create_t &guild);
+ virtual bool OnGuildDelete(const dpp::guild_delete_t &guild);
+ virtual bool OnGuildMemberAdd(const dpp::guild_member_add_t &gma);
+ virtual bool OnMessage(const dpp::message_create_t &message, const std::string& clean_message, bool mentioned, const std::vector<std::string> &stringmentions);
+ virtual bool OnPresenceUpdate();
+ virtual bool OnAllShardsReady();
+ virtual bool OnTypingStart(const dpp::typing_start_t &obj);
+ virtual bool OnMessageUpdate(const dpp::message_update_t &obj);
+ virtual bool OnMessageDelete(const dpp::message_delete_t &obj);
+ virtual bool OnMessageDeleteBulk(const dpp::message_delete_bulk_t &obj);
+ virtual bool OnGuildUpdate(const dpp::guild_update_t &obj);
+ virtual bool OnMessageReactionAdd(const dpp::message_reaction_add_t &obj);
+ virtual bool OnMessageReactionRemove(const dpp::message_reaction_remove_t &obj);
+ virtual bool OnMessageReactionRemoveAll(const dpp::message_reaction_remove_all_t &obj);
+ virtual bool OnUserUpdate(const dpp::user_update_t &obj);
+ virtual bool OnResumed(const dpp::resumed_t &obj);
+ virtual bool OnChannelUpdate(const dpp::channel_update_t &obj);
+ virtual bool OnChannelPinsUpdate(const dpp::channel_pins_update_t &obj);
+ virtual bool OnGuildBanAdd(const dpp::guild_ban_add_t &obj);
+ virtual bool OnGuildBanRemove(const dpp::guild_ban_remove_t &obj);
+ virtual bool OnGuildEmojisUpdate(const dpp::guild_emojis_update_t &obj);
+ virtual bool OnGuildIntegrationsUpdate(const dpp::guild_integrations_update_t &obj);
+ virtual bool OnGuildMemberRemove(const dpp::guild_member_remove_t &obj);
+ virtual bool OnGuildMemberUpdate(const dpp::guild_member_update_t &obj);
+ virtual bool OnGuildMembersChunk(const dpp::guild_members_chunk_t &obj);
+ virtual bool OnGuildRoleCreate(const dpp::guild_role_create_t &obj);
+ virtual bool OnGuildRoleUpdate(const dpp::guild_role_update_t &obj);
+ virtual bool OnGuildRoleDelete(const dpp::guild_role_delete_t &obj);
+ virtual bool OnPresenceUpdateWS(const dpp::presence_update_t &obj);
+ 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);
+};
+
+/* A macro that lets us simply define the entrypoint of a module by name */
+#define ENTRYPOINT(mod_class_name) extern "C" Module* init_module(Bot* instigator, ModuleLoader* ml) { return new mod_class_name(instigator, ml); }
diff --git a/include/142bot/util.hpp b/include/142bot/util.hpp
new file mode 100644
index 0000000..948ad20
--- /dev/null
+++ b/include/142bot/util.hpp
@@ -0,0 +1,85 @@
+
+#include <stdlib.h>
+
+#pragma once
+
+#include <string>
+#include <iomanip>
+#include <locale>
+#include <algorithm>
+
+
+
+/* Simple search and replace, case sensitive */
+std::string ReplaceString(std::string subject, const std::string& search, const std::string& replace);
+/**
+ * Convert a string to lowercase using tolower()
+ */
+template <typename T> std::basic_string<T> lowercase(const std::basic_string<T>& s)
+{
+ std::basic_string<T> s2 = s;
+ std::transform(s2.begin(), s2.end(), s2.begin(), tolower);
+ return std::move(s2);
+}
+
+/**
+ * Convert a string to uppercase using toupper()
+ */
+template <typename T> std::basic_string<T> uppercase(const std::basic_string<T>& s)
+{
+ std::basic_string<T> s2 = s;
+ std::transform(s2.begin(), s2.end(), s2.begin(), toupper);
+ return std::move(s2);
+}
+
+/**
+ * trim from end of string (right)
+ */
+inline std::string rtrim(std::string s)
+{
+ s.erase(s.find_last_not_of(" \t\n\r\f\v") + 1);
+ return s;
+}
+
+/**
+ * trim from beginning of string (left)
+ */
+inline std::string ltrim(std::string s)
+{
+ s.erase(0, s.find_first_not_of(" \t\n\r\f\v"));
+ return s;
+}
+
+/**
+ * trim from both ends of string (right then left)
+ */
+inline std::string trim(std::string s)
+{
+ return ltrim(rtrim(s));
+}
+
+/**
+ * Add commas to a string (or dots) based on current locale server-side
+ */
+template<class T> std::string Comma(T value)
+{
+ std::stringstream ss;
+ ss.imbue(std::locale(""));
+ ss << std::fixed << value;
+ return ss.str();
+}
+
+/**
+ * Convert any value from a string to another type using stringstream.
+ * The optional second parameter indicates the format of the input string,
+ * e.g. std::dec for decimal, std::hex for hex, std::oct for octal.
+ */
+template <typename T> T from_string(const std::string &s, std::ios_base & (*f)(std::ios_base&))
+{
+ T t;
+ std::istringstream iss(s);
+ iss >> f, iss >> t;
+ return t;
+}
+
+