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_REQUIRED ON)
|
||||
|
||||
# Find gloox library
|
||||
cmake_policy(SET CMP0076 NEW)
|
||||
|
||||
find_package(PkgConfig)
|
||||
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})
|
||||
target_link_libraries(jay ${GLOOX_LIBRARIES})
|
||||
set(EXEC_NAME "jay")
|
||||
|
||||
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"
|
||||
|
||||
Jay::Jay(const std::string& jid, const std::string& password) :
|
||||
client(jid, password),
|
||||
loggers(),
|
||||
owners()
|
||||
{
|
||||
client.registerMessageHandler(this);
|
||||
client.registerConnectionListener(this);
|
||||
|
||||
client.setTls(gloox::TLSPolicy::TLSOptional);
|
||||
client.setSASLMechanisms(gloox::SaslMechScramSha1);
|
||||
}
|
||||
Jay::Jay(const std::string& configPath):
|
||||
runMutex(),
|
||||
config(std::make_shared<Config>(configPath)),
|
||||
client(),
|
||||
messageHandler(),
|
||||
connectionHandler(),
|
||||
loggers()
|
||||
{}
|
||||
|
||||
Jay::~Jay() {}
|
||||
|
||||
bool Jay::isConfigValid() const {
|
||||
return config->isValid();
|
||||
}
|
||||
|
||||
|
||||
void Jay::run() {
|
||||
if (client.connect(false)) {
|
||||
// Run the event loop
|
||||
gloox::ConnectionError ce = gloox::ConnNoError;
|
||||
while (ce == gloox::ConnNoError)
|
||||
ce = client.recv();
|
||||
std::lock_guard lock(runMutex);
|
||||
|
||||
std::cout << "Connection terminated with error: " << ce << std::endl;
|
||||
}
|
||||
std::cout << "Out of loop" << std::endl;
|
||||
initialize();
|
||||
client->connect(true);
|
||||
}
|
||||
|
||||
void Jay::handleMessage(const gloox::Message& message, gloox::MessageSession* session) {
|
||||
if (owners.count(message.from().bare())) {
|
||||
std::cout << "Received message from owner: " << message.body() << std::endl;
|
||||
} else {
|
||||
std::cout << "Received message: " << message.body() << std::endl;
|
||||
}
|
||||
void Jay::initialize() {
|
||||
createClient();
|
||||
|
||||
if (!messageHandler)
|
||||
messageHandler = std::make_unique<Message>(config, client);
|
||||
|
||||
if (!connectionHandler)
|
||||
connectionHandler = std::make_unique<Connection>(config, client);
|
||||
}
|
||||
|
||||
void Jay::onConnect() {
|
||||
for (const std::string& owner : owners)
|
||||
client.send(gloox::Message(gloox::Message::Chat, owner, "I'm online!"));
|
||||
}
|
||||
void Jay::createClient() {
|
||||
if (client)
|
||||
return;
|
||||
|
||||
void Jay::onDisconnect(gloox::ConnectionError e) {
|
||||
std::cout << "Disconnected: " << e << std::endl;
|
||||
}
|
||||
client = std::make_shared<gloox::Client>(config->getFullJID(), config->getPassword());
|
||||
addLogger(config->getLogLevel());
|
||||
|
||||
bool Jay::onTLSConnect(const gloox::CertInfo&) {
|
||||
return true;
|
||||
gloox::Disco* disco = client->disco();
|
||||
|
||||
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) {
|
||||
loggers.emplace_back(std::make_unique<Logger>(client.logInstance(), level));
|
||||
return loggers.back().get();
|
||||
}
|
||||
|
||||
void Jay::addOwner(const std::string& jid) {
|
||||
owners.insert(jid);
|
||||
void Jay::addLogger(gloox::LogLevel level) {
|
||||
loggers.emplace_back(std::make_unique<Logger>(client->logInstance(), level));
|
||||
}
|
||||
|
30
jay.h
30
jay.h
@ -4,35 +4,39 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
#include <gloox/client.h>
|
||||
#include <gloox/messagehandler.h>
|
||||
#include <gloox/disco.h>
|
||||
#include <gloox/connectionlistener.h>
|
||||
#include <gloox/message.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:
|
||||
Jay(const std::string& jid, const std::string& password);
|
||||
Jay(const std::string& configPath);
|
||||
~Jay();
|
||||
|
||||
void handleMessage(const gloox::Message& message, gloox::MessageSession* session = 0) override;
|
||||
void onConnect() override;
|
||||
void onDisconnect(gloox::ConnectionError e) override;
|
||||
bool onTLSConnect(const gloox::CertInfo&) override;
|
||||
bool isConfigValid() const;
|
||||
|
||||
void run();
|
||||
|
||||
Logger* addLogger(gloox::LogLevel level);
|
||||
void addOwner(const std::string& jid);
|
||||
private:
|
||||
void addLogger(gloox::LogLevel level);
|
||||
void initialize();
|
||||
void createClient();
|
||||
|
||||
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::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;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
std::string jid = readEnv("JID");
|
||||
std::string password = readEnv("PASSWORD");
|
||||
|
||||
if (jid.empty() || password.empty()) {
|
||||
std::cout << "You need to provide JID and PASSWORD environment variables" << std::endl;
|
||||
return - 1;
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc < 2) {
|
||||
std::cerr << "Usage: " << argv[0] << " <config.yaml>" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
Jay bot(jid, password);
|
||||
bot.addLogger(gloox::LogLevelDebug);
|
||||
|
||||
std::string owners = readEnv("OWNERS");
|
||||
std::stringstream ss(owners);
|
||||
std::string owner;
|
||||
while (std::getline(ss, owner, ','))
|
||||
bot.addOwner(owner);
|
||||
Jay bot(argv[1]);
|
||||
if (!bot.isConfigValid()) {
|
||||
std::cerr << "Invalid config, can not proceed, quitting" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
bot.run();
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user