diff options
Diffstat (limited to 'include')
-rw-r--r-- | include/142bot/bot.hpp | 61 | ||||
-rw-r--r-- | include/142bot/modules.hpp | 192 | ||||
-rw-r--r-- | include/142bot/util.hpp | 85 |
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; +} + + |