From c605b3ba93c5e0f030783e89a4511ef2b57b75fa Mon Sep 17 00:00:00 2001 From: blue Date: Fri, 7 Mar 2025 23:20:06 +0200 Subject: [PATCH] Module creation, message routing --- component/actor.cpp | 3 ++- component/actor.h | 5 ++++- component/config.cpp | 29 +++++++++++++++++++++++++++++ component/config.h | 11 +++++++++++ component/router.cpp | 22 +++++++++++++++++++--- component/router.h | 3 ++- example.config.yml | 12 +++++++++++- handler/message.cpp | 10 +--------- jay.cpp | 19 +++++++++++++++++++ jay.h | 3 +++ module/actor.cpp | 9 +++++---- module/actor.h | 4 ++-- module/module.cpp | 28 +++++++++++++++++++++++++++- module/module.h | 22 +++++++++++++++++++--- 14 files changed, 154 insertions(+), 26 deletions(-) diff --git a/component/actor.cpp b/component/actor.cpp index c03c5d3..f1e97fa 100644 --- a/component/actor.cpp +++ b/component/actor.cpp @@ -3,7 +3,8 @@ #include "actor.h" -Actor::Actor(const std::string& group) : +Actor::Actor(const std::string& jid, const std::string& group) : + jid(jid), group(group) {} diff --git a/component/actor.h b/component/actor.h index e733486..b8c6137 100644 --- a/component/actor.h +++ b/component/actor.h @@ -7,10 +7,13 @@ class Actor { public: - Actor(const std::string& group); + Actor(const std::string& jid, const std::string& group); void setGroup(const std::string& newGroup); +public: + const std::string jid; + private: std::string group; }; diff --git a/component/config.cpp b/component/config.cpp index c9c7f92..9912d64 100644 --- a/component/config.cpp +++ b/component/config.cpp @@ -61,3 +61,32 @@ std::map Config::getOwners() const { bool Config::isValid() const { return !getBareJID().empty() && !getPassword().empty(); } + +Config::Module Config::getModuleConfig(const std::string& name) const { + YAML::Node modules = root["modules"]; + if (!modules || !modules.IsMap()) + return { false }; + + YAML::Node conf = modules[name]; + if (!conf || !conf.IsMap()) + return { false }; + + Module result { + conf["enabled"].as(true), + conf["alias"].as(name) + }; + + YAML::Node prm = conf["permissions"]; + if (prm.IsMap()) { + for (const auto& node : prm) { + Module::List& list = result.permissions.emplace(node.first.as(), Module::List()).first->second; + YAML::Node lst = node.second; + if (lst.IsSequence()) + for (const YAML::Node& member : lst) + list.emplace_back(member.as()); + } + } + + + return result; +} diff --git a/component/config.h b/component/config.h index e92637f..4d2bdeb 100644 --- a/component/config.h +++ b/component/config.h @@ -11,6 +11,16 @@ #include "yaml-cpp/yaml.h" class Config { +public: + struct Module { + typedef std::vector List; + typedef std::map Permissions; + + bool enabled; + std::string alias; + Permissions permissions; + }; + public: Config(const std::string& path); @@ -23,6 +33,7 @@ public: std::map getOwners() const; gloox::LogLevel getLogLevel() const; gloox::TLSPolicy getTLSPolicy() const; + Module getModuleConfig(const std::string& name) const; private: YAML::Node root; diff --git a/component/router.cpp b/component/router.cpp index ea60f50..00576d1 100644 --- a/component/router.cpp +++ b/component/router.cpp @@ -12,7 +12,6 @@ void Router::registerModule(const std::string& key, const std::shared_ptr(key, group)); else - act->second.setGroup(group); + act->second->setGroup(group); } void Router::routeMessage(const std::string& sender, const std::string& body) { + Actors::iterator aItr = actors.find(sender); + if (aItr == actors.end()) + aItr = actors.emplace(sender, std::make_shared(sender, defaultGroup)).first; + + std::vector args = Module::Module::split(body); + Modules::iterator mItr = modules.find(args[0]); + if (mItr == modules.end()) + return; + + std::shared_ptr module = mItr->second.lock(); + if (!module) + return; + + args.erase(args.begin()); + module->message(aItr->second, args); } + + diff --git a/component/router.h b/component/router.h index ff3ee92..e8e3039 100644 --- a/component/router.h +++ b/component/router.h @@ -5,6 +5,7 @@ #include #include +#include #include #include "actor.h" @@ -20,7 +21,7 @@ public: private: typedef std::map> Modules; - typedef std::map Actors; + typedef std::map> Actors; Modules modules; Actors actors; diff --git a/example.config.yml b/example.config.yml index 12eb9aa..9f6a4a7 100644 --- a/example.config.yml +++ b/example.config.yml @@ -1,9 +1,19 @@ +logLevel: debug + jid: bot@xmpp.server password: "supersecret" -logLevel: debug tls: required resource: bot + actors: user1@xmpp.server: Owner user2@xmpp.server: User default: Stranger + +modules: + actor: + alias: actor + enabled: true + permissions: + - read: [Owner, User] + - write: [Owner] diff --git a/handler/message.cpp b/handler/message.cpp index f7eec78..86dab2e 100644 --- a/handler/message.cpp +++ b/handler/message.cpp @@ -19,13 +19,5 @@ Message::~Message() { } void Message::handleMessage(const gloox::Message& message, gloox::MessageSession* session) { - std::shared_ptr cfg = config.lock(); - if (!cfg) - return; - - if (cfg->getOwners().count(message.from().bare())) { - std::cout << "Received message from owner: " << message.body() << std::endl; - } else { - std::cout << "Received message: " << message.body() << std::endl; - } + callback(message.from().bare(), message.body()); } diff --git a/jay.cpp b/jay.cpp index 460fe6a..b88928d 100644 --- a/jay.cpp +++ b/jay.cpp @@ -3,6 +3,13 @@ #include "jay.h" +#include "module/actor.h" + +static const std::map(const std::shared_ptr)>> moduleNames = { + {"actor", [](const std::shared_ptr client) { return std::make_shared(client); }} + +}; + Jay::Jay(const std::string& configPath): runMutex(), config(std::make_shared(configPath)), @@ -10,6 +17,7 @@ Jay::Jay(const std::string& configPath): client(), messageHandler(), connectionHandler(), + modules(), loggers() {} @@ -40,6 +48,7 @@ void Jay::initialize() { if (!connectionHandler) connectionHandler = std::make_unique(config, client); + createModules(); createActors(); } @@ -65,6 +74,16 @@ void Jay::createActors() { router->registerActor(pair.first, pair.second); } +void Jay::createModules() { + for (const auto& pair : moduleNames) { + Config::Module conf = config->getModuleConfig(pair.first); + if (!conf.enabled) + continue; + + modules.emplace_back(pair.second(client)); + router->registerModule(pair.first, modules.back()); + } +} void Jay::addLogger(gloox::LogLevel level) { loggers.emplace_back(std::make_unique(client->logInstance(), level)); diff --git a/jay.h b/jay.h index ec4bc92..66a66c2 100644 --- a/jay.h +++ b/jay.h @@ -18,6 +18,7 @@ #include "component/router.h" #include "handler/message.h" #include "handler/connection.h" +#include "module/module.h" class Jay { public: @@ -33,6 +34,7 @@ private: void initialize(); void createClient(); void createActors(); + void createModules(); private: std::mutex runMutex; @@ -41,5 +43,6 @@ private: std::shared_ptr client; std::unique_ptr messageHandler; std::unique_ptr connectionHandler; + std::vector> modules; std::vector> loggers; }; diff --git a/module/actor.cpp b/module/actor.cpp index 7450e4c..7188ec0 100644 --- a/module/actor.cpp +++ b/module/actor.cpp @@ -3,12 +3,13 @@ #include "actor.h" -Module::Actor::Actor(): - Module() +Module::Actor::Actor(const std::shared_ptr& client): + Module(client) {} Module::Actor::~Actor() noexcept {} -void Module::Actor::message(const std::string& text) { - +void Module::Actor::message(const std::shared_ptr<::Actor>& actor, const Module::Module::Tokens& args) { + if (args.front() == "list") + sendMessage(actor, "Me\nMyself\nI"); } diff --git a/module/actor.h b/module/actor.h index c7dca03..66d31bf 100644 --- a/module/actor.h +++ b/module/actor.h @@ -9,10 +9,10 @@ namespace Module { class Actor : public Module { public: - Actor(); + Actor(const std::shared_ptr& client); ~Actor() noexcept; - virtual void message(const std::string & text) override; + virtual void message(const std::shared_ptr<::Actor>& actor, const Tokens& args) override; }; } diff --git a/module/module.cpp b/module/module.cpp index 0d500db..557fb5d 100644 --- a/module/module.cpp +++ b/module/module.cpp @@ -3,7 +3,33 @@ #include "module.h" -Module::Module::Module() +#include "gloox/message.h" + +Module::Module::Module(const std::shared_ptr& client): + client(client) {} Module::Module::~Module() noexcept {} + +std::vector Module::Module::split(const std::string& string, const std::string& delimiter) { + std::vector result; + + std::size_t last = 0; + std::size_t next = string.find(delimiter, last); + while (next != std::string::npos) { + result.emplace_back(string.substr(last, next - last)); + last = next + 1; + next = string.find(delimiter, last); + } + result.emplace_back(string.substr(last)); + + return result; +} + +void Module::Module::sendMessage(const std::shared_ptr& actor, const std::string& body) { + client->send(gloox::Message( + gloox::Message::Chat, + actor->jid, + body + )); +} diff --git a/module/module.h b/module/module.h index 888b700..1c97233 100644 --- a/module/module.h +++ b/module/module.h @@ -4,17 +4,33 @@ #pragma once #include +#include +#include + +#include "gloox/client.h" + +#include "component/actor.h" namespace Module { class Module { -protected: - Module(); +public: + typedef std::vector Tokens; - virtual void message(const std::string& text) = 0; +protected: + Module(const std::shared_ptr& client); + void sendMessage(const std::shared_ptr& actor, const std::string& body); public: virtual ~Module() noexcept; + + static Tokens split(const std::string& string, const std::string& delimiter = " "); + + virtual void message(const std::shared_ptr& actor, const Tokens& args) = 0; + +protected: + std::shared_ptr client; + }; }