Logging of the messages, customizable replies, assigning groups

This commit is contained in:
Blue 2025-03-15 22:34:50 +02:00
parent f03f392cee
commit 7f57cd3bf6
Signed by: blue
GPG key ID: 9B203B252A63EE38
21 changed files with 288 additions and 62 deletions

View file

@ -85,7 +85,7 @@ Config::Module Config::getModuleConfig(const std::string& name) const {
YAML::Node prm = conf["permissions"];
if (prm.IsMap()) {
for (const auto& node : prm) {
Module::List& list = result.permissions.emplace(node.first.as<std::string>(), Module::List()).first->second;
Shared::Strings& list = result.permissions.emplace(node.first.as<std::string>(), Shared::Strings()).first->second;
YAML::Node lst = node.second;
if (lst.IsSequence())
for (const YAML::Node& member : lst)
@ -93,6 +93,25 @@ Config::Module Config::getModuleConfig(const std::string& name) const {
}
}
return result;
}
Shared::Responses Config::getResponses() const {
Shared::Responses responses;
YAML::Node replies = root["replies"];
if (!replies || !replies.IsMap())
return responses;
for (const std::pair<Shared::Result, std::string_view>& entry : Shared::results) {
YAML::Node options = replies[entry.second];
if (!options.IsSequence())
continue;
Shared::Strings& out = responses.emplace(entry.first, Shared::Strings()).first->second;
for (const YAML::Node& option : options)
out.emplace_back(option.as<std::string>());
}
return responses;
}

View file

@ -10,17 +10,16 @@
#include "yaml-cpp/yaml.h"
#include "shared/definitions.h"
#include "shared/result.h"
#include "logger.h"
class Config {
public:
struct Module {
typedef std::vector<std::string> List;
typedef std::map<std::string, List> Permissions;
bool enabled;
std::string alias;
Permissions permissions;
Shared::Permissions permissions;
};
public:
@ -36,6 +35,7 @@ public:
Logger::Level getLogLevel() const;
gloox::TLSPolicy getTLSPolicy() const;
Module getModuleConfig(const std::string& name) const;
Shared::Responses getResponses() const;
private:
YAML::Node root;

View file

@ -3,8 +3,51 @@
#include "core.h"
#include "connection/connection.h"
Core::Core(const std::string& configPath):
config(configPath),
router(),
logger(config.getLogLevel())
logger(config.getLogLevel()),
router(logger),
initialized(false)
{}
void Core::send(const std::string& jid, const std::string& body) {
std::shared_ptr<Connection> cn = connection.lock();
if (!cn) {
logger.log(Logger::warning, "Couldn't send a message to " + jid + ", connection is not available", {"Core"});
return;
}
cn->send(jid, body);
}
void Core::initialize(const std::shared_ptr<Connection>& cn) {
connection = cn;
router.setConnection(cn);
if (initialized)
return;
initializeActors();
initializeResponses();
initialized = true;
}
void Core::setGroup(const std::string& jid, const std::string& group) {
router.registerActor(jid, group);
// todo save config
}
void Core::initializeActors() {
for (const std::pair<const std::string, std::string>& pair : config.getActors()) {
logger.log(Logger::info, "registering actor " + pair.first + " as " + pair.second, {"Core"});
router.registerActor(pair.first, pair.second);
}
}
void Core::initializeResponses() {
for (const std::pair<Shared::Result, Shared::Strings>& pair : config.getResponses())
router.setResponses(pair.first, pair.second);
}

View file

@ -4,17 +4,33 @@
#pragma once
#include <string>
#include <memory>
#include "config.h"
#include "router.h"
#include "logger.h"
class Connection;
class Core {
public:
Core(const std::string& configPath);
void send(const std::string& jid, const std::string& body);
void initialize(const std::shared_ptr<Connection>& connection);
void setGroup(const std::string& jid, const std::string& group);
public:
Config config;
Router router;
Logger logger;
Router router;
private:
void initializeActors();
void initializeResponses();
private:
bool initialized;
std::weak_ptr<Connection> connection;
};

View file

@ -129,7 +129,7 @@ void Logger::handleLog(gloox::LogLevel level, gloox::LogArea area, const std::st
std::cout << clear << '\t' << message << clear << std::endl;
}
void Logger::log(Level lvl, const std::string& message, const std::vector<std::string>& domain) {
void Logger::log(Level lvl, const std::string& message, const std::vector<std::string>& domain) const {
if (lvl < level)
return;

View file

@ -25,7 +25,7 @@ public:
void handleLog(gloox::LogLevel level, gloox::LogArea area, const std::string& message) override;
void log(Level level, const std::string& message, const std::vector<std::string>& domain = {});
void log(Level level, const std::string& message, const std::vector<std::string>& domain = {}) const;
static gloox::LogLevel convert(Level level);
static Level convert(gloox::LogLevel level);

View file

@ -4,10 +4,19 @@
#include "router.h"
#include "module/module.h"
#include "connection/connection.h"
Router::Router():
Router::Router(const Logger& logger):
logger(logger),
modules(),
actors(),
defaultGroup("Stranger")
defaultGroup("Stranger"),
responses({
{Shared::forbidden, { "Forbidden" }},
{Shared::error, { "Command error" }},
{Shared::unhandled, { "No such command" }},
}),
generator(std::random_device{}())
{}
void Router::registerModule(const std::string& key, const std::shared_ptr<Module::Module>& module) {
@ -34,15 +43,29 @@ void Router::routeMessage(const std::string& sender, const std::string& body) {
std::vector<std::string> args = Module::Module::split(body);
Modules::iterator mItr = modules.find(args[0]);
if (mItr == modules.end())
return;
if (mItr == modules.end()) {
logger.log(Logger::debug, "could not find module \"" + args[0] + "\" to handle message from " + sender, {"Router"});
return onMessageResult(Shared::unhandled, sender);
}
std::shared_ptr<Module::Module> module = mItr->second.lock();
if (!module)
return;
if (!module) {
logger.log(Logger::error, "could not lock module \"" + mItr->first + "\" to handle message from " + sender, {"Router"});
return onMessageResult(Shared::error, sender);
}
args.erase(args.begin());
module->message(aItr->second, args);
Shared::Result result;
try {
result = module->message(aItr->second, args);
if (result == Shared::success)
logger.log(Logger::debug, "module \"" + mItr->first + "\" successfully handled message from " + sender, {"Router"});
} catch (...) {
logger.log(Logger::error, "module \"" + mItr->first + "\" thew an unhandled exception handling message from " + sender, {"Router"});
result = Shared::error;
}
onMessageResult(result, sender);
}
std::map<std::string, std::string> Router::getActors() const {
@ -54,4 +77,35 @@ std::map<std::string, std::string> Router::getActors() const {
return result;
}
void Router::setConnection(const std::shared_ptr<Connection>& cn) {
connection = cn;
}
void Router::setResponses(Shared::Result result, const Shared::Strings& options) {
responses[result] = options;
}
std::string Router::getGroup(const std::string& key) const {
Actors::const_iterator itr = actors.find(key);
if (itr == actors.end())
return defaultGroup;
return itr->second->getGroup();
}
void Router::onMessageResult(Shared::Result result, const std::string& sender) {
Responses::const_iterator rItr = responses.find(result);
if (rItr == responses.end() || rItr->second.empty())
return;
std::shared_ptr<Connection> cn = connection.lock();
if (!cn) {
logger.log(Logger::warning, "Couldn't send a message to " + sender + ", connection is not available", {"Router"});
return;
}
const List& options = rItr->second;
std::uniform_int_distribution<std::size_t> dist(0, options.size() - 1);
cn->send(sender, options[dist(generator)]);
}

View file

@ -7,16 +7,21 @@
#include <map>
#include <vector>
#include <memory>
#include <random>
#include "shared/result.h"
#include "actor.h"
#include "logger.h"
namespace Module {
class Module;
};
class Connection;
class Router {
public:
Router();
Router(const Logger& logger);
void registerModule(const std::string& key, const std::shared_ptr<Module::Module>& module);
void registerActor(const std::string& key, const std::string& group);
@ -24,11 +29,24 @@ public:
std::map<std::string, std::string> getActors() const;
void setConnection(const std::shared_ptr<Connection>& connection);
void setResponses(Shared::Result result, const Shared::Strings& options);
std::string getGroup(const std::string& key) const;
private:
void onMessageResult(Shared::Result result, const std::string& sender);
private:
typedef std::map<std::string, std::weak_ptr<Module::Module>> Modules;
typedef std::map<std::string, std::shared_ptr<Actor>> Actors;
typedef std::vector<std::string> List;
typedef std::map<Shared::Result, List> Responses;
std::weak_ptr<Connection> connection;
const Logger& logger;
Modules modules;
Actors actors;
std::string defaultGroup;
Responses responses;
std::mt19937 generator;
};