Yaml config
This commit is contained in:
parent
698e706daa
commit
46695c8aab
@ -7,13 +7,29 @@ project(jay
|
|||||||
set(CMAKE_CXX_STANDARD 20)
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
# Find gloox library
|
cmake_policy(SET CMP0076 NEW)
|
||||||
|
|
||||||
find_package(PkgConfig)
|
find_package(PkgConfig)
|
||||||
pkg_search_module(GLOOX REQUIRED gloox)
|
pkg_search_module(GLOOX REQUIRED gloox)
|
||||||
|
|
||||||
add_executable(jay main.cpp jay.cpp logger.cpp)
|
find_package(yaml-cpp REQUIRED)
|
||||||
|
|
||||||
target_include_directories(jay PRIVATE ${GLOOX_INCLUDE_DIRS})
|
set(EXEC_NAME "jay")
|
||||||
target_link_libraries(jay ${GLOOX_LIBRARIES})
|
|
||||||
|
|
||||||
install(TARGETS jay RUNTIME DESTINATION bin)
|
add_executable(${EXEC_NAME}
|
||||||
|
main.cpp
|
||||||
|
jay.cpp
|
||||||
|
logger.cpp
|
||||||
|
config.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
add_subdirectory(handlers)
|
||||||
|
|
||||||
|
target_include_directories(${EXEC_NAME} PRIVATE ${GLOOX_INCLUDE_DIRS})
|
||||||
|
target_include_directories(${EXEC_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
target_link_libraries(${EXEC_NAME} PRIVATE
|
||||||
|
${GLOOX_LIBRARIES}
|
||||||
|
yaml-cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
install(TARGETS ${EXEC_NAME} RUNTIME DESTINATION bin)
|
||||||
|
63
config.cpp
Normal file
63
config.cpp
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2024 Yury Gubich <blue@macaw.me>
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
Config::Config(const std::string& path):
|
||||||
|
root(YAML::LoadFile(path))
|
||||||
|
{}
|
||||||
|
|
||||||
|
std::string Config::getBareJID() const {
|
||||||
|
return root["jid"].as<std::string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Config::getPassword() const {
|
||||||
|
return root["password"].as<std::string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Config::getResource() const {
|
||||||
|
return root["resource"].as<std::string>("bot");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Config::getFullJID() const {
|
||||||
|
return getBareJID() + "/" + getResource();
|
||||||
|
}
|
||||||
|
|
||||||
|
gloox::LogLevel Config::getLogLevel() const {
|
||||||
|
std::string level = root["logLevel"].as<std::string>("warning");
|
||||||
|
|
||||||
|
if (level == "debug")
|
||||||
|
return gloox::LogLevelDebug;
|
||||||
|
else if (level == "error")
|
||||||
|
return gloox::LogLevelError;
|
||||||
|
else
|
||||||
|
return gloox::LogLevelWarning;
|
||||||
|
}
|
||||||
|
|
||||||
|
gloox::TLSPolicy Config::getTLSPolicy() const {
|
||||||
|
std::string level = root["tls"].as<std::string>("optional");
|
||||||
|
|
||||||
|
if (level == "disabled")
|
||||||
|
return gloox::TLSDisabled;
|
||||||
|
else if (level == "required")
|
||||||
|
return gloox::TLSRequired;
|
||||||
|
else
|
||||||
|
return gloox::TLSOptional;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::set<std::string> Config::getOwners() const {
|
||||||
|
std::set<std::string> result;
|
||||||
|
YAML::Node owners = root["resource"];
|
||||||
|
if (!owners.IsSequence())
|
||||||
|
return result;
|
||||||
|
|
||||||
|
for (const YAML::Node& node : owners)
|
||||||
|
result.insert(node.as<std::string>());
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Config::isValid() const {
|
||||||
|
return !getBareJID().empty() && !getPassword().empty();
|
||||||
|
}
|
29
config.h
Normal file
29
config.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2024 Yury Gubich <blue@macaw.me>
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
#include "gloox/gloox.h"
|
||||||
|
|
||||||
|
#include "yaml-cpp/yaml.h"
|
||||||
|
|
||||||
|
class Config {
|
||||||
|
public:
|
||||||
|
Config(const std::string& path);
|
||||||
|
|
||||||
|
bool isValid() const;
|
||||||
|
|
||||||
|
std::string getBareJID() const;
|
||||||
|
std::string getFullJID() const;
|
||||||
|
std::string getPassword() const;
|
||||||
|
std::string getResource() const;
|
||||||
|
std::set<std::string> getOwners() const;
|
||||||
|
gloox::LogLevel getLogLevel() const;
|
||||||
|
gloox::TLSPolicy getTLSPolicy() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
YAML::Node root;
|
||||||
|
};
|
8
example.config.yml
Normal file
8
example.config.yml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
jid: bot@xmpp.server
|
||||||
|
password: "supersecret"
|
||||||
|
logLevel: debug
|
||||||
|
tls: required
|
||||||
|
resource: bot
|
||||||
|
owners:
|
||||||
|
- user1@xmpp.server
|
||||||
|
- user2@xmpp.server
|
11
handlers/CMakeLists.txt
Normal file
11
handlers/CMakeLists.txt
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
set(SOURCES
|
||||||
|
message.cpp
|
||||||
|
connection.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(HEADERS
|
||||||
|
message.h
|
||||||
|
connection.h
|
||||||
|
)
|
||||||
|
|
||||||
|
target_sources(${EXEC_NAME} PRIVATE ${SOURCES})
|
27
handlers/connection.cpp
Normal file
27
handlers/connection.cpp
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2024 Yury Gubich <blue@macaw.me>
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#include "connection.h"
|
||||||
|
|
||||||
|
Connection::Connection(const std::shared_ptr<Config>& config, const std::shared_ptr<gloox::Client>& client):
|
||||||
|
config(config),
|
||||||
|
client(client)
|
||||||
|
{
|
||||||
|
client->registerConnectionListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Connection::~Connection() {
|
||||||
|
if (std::shared_ptr<gloox::Client> cl = client.lock())
|
||||||
|
cl->removeConnectionListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Connection::onConnect() {}
|
||||||
|
|
||||||
|
void Connection::onDisconnect(gloox::ConnectionError e) {}
|
||||||
|
|
||||||
|
bool Connection::onTLSConnect(const gloox::CertInfo&) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
25
handlers/connection.h
Normal file
25
handlers/connection.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2024 Yury Gubich <blue@macaw.me>
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "gloox/client.h"
|
||||||
|
#include "gloox/connectionlistener.h"
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
class Connection : public gloox::ConnectionListener {
|
||||||
|
public:
|
||||||
|
Connection(const std::shared_ptr<Config>& config, const std::shared_ptr<gloox::Client>& client);
|
||||||
|
~Connection();
|
||||||
|
|
||||||
|
void onConnect() override;
|
||||||
|
void onDisconnect(gloox::ConnectionError e) override;
|
||||||
|
bool onTLSConnect(const gloox::CertInfo&) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::weak_ptr<Config> config;
|
||||||
|
std::weak_ptr<gloox::Client> client;
|
||||||
|
};
|
30
handlers/message.cpp
Normal file
30
handlers/message.cpp
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2024 Yury Gubich <blue@macaw.me>
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#include "message.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
Message::Message(const std::shared_ptr<Config>& config, const std::shared_ptr<gloox::Client>& client):
|
||||||
|
config(config),
|
||||||
|
client(client)
|
||||||
|
{
|
||||||
|
client->registerMessageHandler(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Message::~Message() {
|
||||||
|
if (std::shared_ptr<gloox::Client> cl = client.lock())
|
||||||
|
cl->removeMessageHandler(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Message::handleMessage(const gloox::Message& message, gloox::MessageSession* session) {
|
||||||
|
std::shared_ptr<Config> 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;
|
||||||
|
}
|
||||||
|
}
|
24
handlers/message.h
Normal file
24
handlers/message.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2024 Yury Gubich <blue@macaw.me>
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <gloox/client.h>
|
||||||
|
#include <gloox/messagehandler.h>
|
||||||
|
#include <gloox/message.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
class Message : public gloox::MessageHandler {
|
||||||
|
public:
|
||||||
|
Message(const std::shared_ptr<Config>& config, const std::shared_ptr<gloox::Client>& client);
|
||||||
|
~Message();
|
||||||
|
|
||||||
|
void handleMessage(const gloox::Message& message, gloox::MessageSession* session = 0) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::weak_ptr<Config> config;
|
||||||
|
std::weak_ptr<gloox::Client> client;
|
||||||
|
};
|
80
jay.cpp
80
jay.cpp
@ -3,59 +3,57 @@
|
|||||||
|
|
||||||
#include "jay.h"
|
#include "jay.h"
|
||||||
|
|
||||||
Jay::Jay(const std::string& jid, const std::string& password) :
|
Jay::Jay(const std::string& configPath):
|
||||||
client(jid, password),
|
runMutex(),
|
||||||
loggers(),
|
config(std::make_shared<Config>(configPath)),
|
||||||
owners()
|
client(),
|
||||||
{
|
messageHandler(),
|
||||||
client.registerMessageHandler(this);
|
connectionHandler(),
|
||||||
client.registerConnectionListener(this);
|
loggers()
|
||||||
|
{}
|
||||||
client.setTls(gloox::TLSPolicy::TLSOptional);
|
|
||||||
client.setSASLMechanisms(gloox::SaslMechScramSha1);
|
|
||||||
}
|
|
||||||
|
|
||||||
Jay::~Jay() {}
|
Jay::~Jay() {}
|
||||||
|
|
||||||
|
bool Jay::isConfigValid() const {
|
||||||
|
return config->isValid();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Jay::run() {
|
void Jay::run() {
|
||||||
if (client.connect(false)) {
|
std::lock_guard lock(runMutex);
|
||||||
// Run the event loop
|
|
||||||
gloox::ConnectionError ce = gloox::ConnNoError;
|
|
||||||
while (ce == gloox::ConnNoError)
|
|
||||||
ce = client.recv();
|
|
||||||
|
|
||||||
std::cout << "Connection terminated with error: " << ce << std::endl;
|
initialize();
|
||||||
}
|
client->connect(true);
|
||||||
std::cout << "Out of loop" << std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Jay::handleMessage(const gloox::Message& message, gloox::MessageSession* session) {
|
void Jay::initialize() {
|
||||||
if (owners.count(message.from().bare())) {
|
createClient();
|
||||||
std::cout << "Received message from owner: " << message.body() << std::endl;
|
|
||||||
} else {
|
if (!messageHandler)
|
||||||
std::cout << "Received message: " << message.body() << std::endl;
|
messageHandler = std::make_unique<Message>(config, client);
|
||||||
}
|
|
||||||
|
if (!connectionHandler)
|
||||||
|
connectionHandler = std::make_unique<Connection>(config, client);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Jay::onConnect() {
|
void Jay::createClient() {
|
||||||
for (const std::string& owner : owners)
|
if (client)
|
||||||
client.send(gloox::Message(gloox::Message::Chat, owner, "I'm online!"));
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
void Jay::onDisconnect(gloox::ConnectionError e) {
|
client = std::make_shared<gloox::Client>(config->getFullJID(), config->getPassword());
|
||||||
std::cout << "Disconnected: " << e << std::endl;
|
addLogger(config->getLogLevel());
|
||||||
}
|
|
||||||
|
|
||||||
bool Jay::onTLSConnect(const gloox::CertInfo&) {
|
gloox::Disco* disco = client->disco();
|
||||||
return true;
|
|
||||||
|
disco->setVersion("Jay", "0.0.1");
|
||||||
|
disco->setIdentity("client", "bot");
|
||||||
|
|
||||||
|
client->setTls(config->getTLSPolicy());
|
||||||
|
client->setSASLMechanisms(gloox::SaslMechAll);
|
||||||
|
client->setStreamManagement(true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Logger* Jay::addLogger(gloox::LogLevel level) {
|
void Jay::addLogger(gloox::LogLevel level) {
|
||||||
loggers.emplace_back(std::make_unique<Logger>(client.logInstance(), level));
|
loggers.emplace_back(std::make_unique<Logger>(client->logInstance(), level));
|
||||||
return loggers.back().get();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jay::addOwner(const std::string& jid) {
|
|
||||||
owners.insert(jid);
|
|
||||||
}
|
}
|
||||||
|
30
jay.h
30
jay.h
@ -4,35 +4,39 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <set>
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
#include <gloox/client.h>
|
#include <gloox/client.h>
|
||||||
#include <gloox/messagehandler.h>
|
#include <gloox/disco.h>
|
||||||
#include <gloox/connectionlistener.h>
|
#include <gloox/connectionlistener.h>
|
||||||
#include <gloox/message.h>
|
|
||||||
|
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "handlers/message.h"
|
||||||
|
#include "handlers/connection.h"
|
||||||
|
|
||||||
class Jay : public gloox::MessageHandler, public gloox::ConnectionListener {
|
class Jay {
|
||||||
public:
|
public:
|
||||||
Jay(const std::string& jid, const std::string& password);
|
Jay(const std::string& configPath);
|
||||||
~Jay();
|
~Jay();
|
||||||
|
|
||||||
void handleMessage(const gloox::Message& message, gloox::MessageSession* session = 0) override;
|
bool isConfigValid() const;
|
||||||
void onConnect() override;
|
|
||||||
void onDisconnect(gloox::ConnectionError e) override;
|
|
||||||
bool onTLSConnect(const gloox::CertInfo&) override;
|
|
||||||
|
|
||||||
void run();
|
void run();
|
||||||
|
|
||||||
Logger* addLogger(gloox::LogLevel level);
|
private:
|
||||||
void addOwner(const std::string& jid);
|
void addLogger(gloox::LogLevel level);
|
||||||
|
void initialize();
|
||||||
|
void createClient();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
gloox::Client client;
|
std::mutex runMutex;
|
||||||
|
std::shared_ptr<Config> config;
|
||||||
|
std::shared_ptr<gloox::Client> client;
|
||||||
|
std::unique_ptr<Message> messageHandler;
|
||||||
|
std::unique_ptr<Connection> connectionHandler;
|
||||||
std::vector<std::unique_ptr<Logger>> loggers;
|
std::vector<std::unique_ptr<Logger>> loggers;
|
||||||
std::set<std::string> owners;
|
|
||||||
};
|
};
|
||||||
|
24
main.cpp
24
main.cpp
@ -16,23 +16,17 @@ std::string readEnv(const std::string& key, const std::string& defaultValue = ""
|
|||||||
return defaultValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char* argv[]) {
|
||||||
std::string jid = readEnv("JID");
|
if (argc < 2) {
|
||||||
std::string password = readEnv("PASSWORD");
|
std::cerr << "Usage: " << argv[0] << " <config.yaml>" << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
if (jid.empty() || password.empty()) {
|
|
||||||
std::cout << "You need to provide JID and PASSWORD environment variables" << std::endl;
|
|
||||||
return - 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Jay bot(jid, password);
|
Jay bot(argv[1]);
|
||||||
bot.addLogger(gloox::LogLevelDebug);
|
if (!bot.isConfigValid()) {
|
||||||
|
std::cerr << "Invalid config, can not proceed, quitting" << std::endl;
|
||||||
std::string owners = readEnv("OWNERS");
|
return EXIT_FAILURE;
|
||||||
std::stringstream ss(owners);
|
}
|
||||||
std::string owner;
|
|
||||||
while (std::getline(ss, owner, ','))
|
|
||||||
bot.addOwner(owner);
|
|
||||||
|
|
||||||
bot.run();
|
bot.run();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user