1
0
Fork 0
mirror of https://gitlab.com/niansa/asbots.git synced 2025-03-06 20:48:25 +01:00

Added configuration parser

This commit is contained in:
Nils 2021-06-21 12:18:40 +02:00
parent 085ff14ea6
commit ee52874033
13 changed files with 150 additions and 42 deletions

View file

@ -11,7 +11,7 @@ add_executable(asbots
utility.cpp
serviceBase.cpp
services/test.cpp
config.cpp
configParser.cpp
)
find_package(PkgConfig REQUIRED)
@ -19,3 +19,5 @@ pkg_check_modules(libasync-uv REQUIRED IMPORTED_TARGET libasync-uv)
pkg_check_modules(fmt REQUIRED IMPORTED_TARGET fmt)
target_link_libraries(asbots PRIVATE PkgConfig::libasync-uv PkgConfig::fmt)
configure_file(config.inil config.inil COPYONLY)

View file

@ -1,19 +0,0 @@
#include "config.hpp"
Config config = {
.connection = {
.addr = "127.0.0.1",
.port = 6667,
},
.auth = {
.send_password = "849372523412",
.accept_password = "843574835765"
},
.server = {
.name = "services.",
.description = "A test service!!",
.uid = "23X"
}
};

View file

@ -3,10 +3,17 @@
#include "uid.hpp"
#include <string>
#include <unordered_map>
#include <filesystem>
#include <stdexcept>
struct Config {
struct ParseError : public std::runtime_error {
using std::runtime_error::runtime_error;
};
struct Connection {
std::string addr;
int port;
@ -19,5 +26,10 @@ struct Config {
SUID uid; // Fourth one reserved for null-terminator
bool hidden = false;
} server;
} extern config;
std::unordered_map<std::string, std::unordered_map<std::string, std::string>> misc;
};
Config parseConfig(const std::filesystem::path& path);
#endif

19
config.inil Normal file
View file

@ -0,0 +1,19 @@
[connection]
addr: 127.0.0.1
port: 6667
end
[auth]
send_password: 849372523412
accept_password: 843574835765
end
[server]
name: services.
description: A test service!!
uid: 23X
end
[testservice]
channel: #testservice
end

75
configParser.cpp Normal file
View file

@ -0,0 +1,75 @@
#include "config.hpp"
#include "uid.hpp"
#include "utility.hpp"
#include <string>
#include <string_view>
#include <tuple>
#include <fstream>
#include <filesystem>
inline void noop() {}
Config parseConfig(const std::filesystem::path& path) {
Config fres;
auto file = std::ifstream(path);
// Read through all sections
while (!file.eof()) {
std::string head;
std::string_view section;
file >> head;
// Skip some emptynes
if (head.empty()) {
continue;
}
// Check section head syntax
if (head.size() < 3 || !head.starts_with('[') || !head.ends_with(']')) {
throw Config::ParseError("Invalid head (section identifier) syntax");
}
// Extract actual section name
section = {head.data()+1, head.size()-2};
while (!file.eof()) {
// Get key and value
std::string line;
std::getline(file, line);
// Check for empty line
if (line.empty()) {
continue;
}
// Split into key and value
auto [key, value] = Utility::splitOnce(line, ": ");
// Check for "end"
if (key == "end") {
break;
}
// Do stuff depending on current section using macro magic
# define SECTION(name, ...) if (section == #name) {auto &d = fres.name; __VA_ARGS__; continue;;} noop()
# define ASSIGN(e_key, val) if (key == #e_key) {d.e_key = val; continue;} noop()
SECTION(connection, {
ASSIGN(addr, value);
ASSIGN(port, std::stoi(std::string(value)));
});
SECTION(auth, {
ASSIGN(send_password, value);
ASSIGN(accept_password, value);
});
SECTION(server, {
ASSIGN(name, value);
ASSIGN(description, value);
ASSIGN(uid, SUID(value));
ASSIGN(hidden, value=="true");
});
// Misc keys
auto s_res = fres.misc.find(std::string(section));
if (s_res == fres.misc.end()) {
fres.misc[std::string(section)] = {{std::string(key), std::string(value)}};
} else {
s_res->second[std::string(key)] = value;
}
}
}
// Return resulting Config object
return fres;
}

View file

@ -34,7 +34,7 @@ void Event::parse(std::string_view str) {
name = std::move(split[1]);
if (split.size() == 3) {
// Get args and text
std::tie(raw_args, text) = colonSplit(split[2]);
std::tie(raw_args, text) = splitOnce(split[2], " :");
}
}
@ -43,7 +43,7 @@ void Command::parse(std::string_view str) {
auto split = strSplit(str, ' ', 1);
name = std::move(split[0]);
// Get text from args
std::tie(args, text) = colonSplit(split[1]);
std::tie(args, text) = splitOnce(split[1], " :");
}
@ -248,9 +248,9 @@ async::result<void> Instance::run() {
}
async::result<void> Instance::login() {
co_await socket->send("PASS {} TS 6 :{}\n"_format(config.get().auth.send_password, config.get().server.uid.str()));
co_await socket->send("PASS {} TS 6 :{}\n"_format(config.auth.send_password, config.server.uid.str()));
co_await socket->send("CAPAB :QS EX IE KLN UNKLN ENCAP TB SERVICES EUID EOPMOD MLOCK\n"sv);
co_await socket->send("SERVER {} 1 :{}{}\n"_format(config.get().server.name, config.get().server.hidden ? "(H) " : "", config.get().server.description));
co_await socket->send("SERVER {} 1 :{}{}\n"_format(config.server.name, config.server.hidden ? "(H) " : "", config.server.description));
co_await socket->send("SVINFO 6 3 0 :{}\n"_format(time(nullptr)));
}
@ -268,7 +268,7 @@ async::result<void> Instance::process(const Command command) {
if (command.name == "PASS") {
// Check password
auto given_password = strSplit(command.args, ' ', 1)[0];
if (given_password != config.get().auth.accept_password) {
if (given_password != config.auth.accept_password) {
throw ConnectionError("Server supplied wrong password during authentication");
}
authed = true;
@ -277,7 +277,7 @@ async::result<void> Instance::process(const Command command) {
} else if (command.name == "ERROR") {
throw ConnectionError(command.dump());
} else if (command.name == "SQUIT") {
if (command.args == config.get().server.uid.str()) {
if (command.args == config.server.uid.str()) {
throw ConnectionError(command.dump());
}
} else if (!authed) {
@ -294,7 +294,7 @@ async::result<void> Instance::process(const Command command) {
co_await burst();
}
// Reply
co_await socket->send(":{} PONG {} {} :{}\n"_format(config.get().server.uid.str(), config.get().server.name, command.args, command.text));
co_await socket->send(":{} PONG {} {} :{}\n"_format(config.server.uid.str(), config.server.name, command.args, command.text));
}
}
@ -307,7 +307,7 @@ async::result<void> Instance::process(Event event) {
// Fetched info
else if (event.name == "005") {
// Check if that 005 was for me
if (event.args[0] != config.get().server.uid.str()) {
if (event.args[0] != config.server.uid.str()) {
co_return;
}
// Split the list

View file

@ -227,7 +227,7 @@ class Instance {
public:
std::unique_ptr<uvpp::tcp> socket;
std::reference_wrapper<const Config> config;
const Config config;
Config::Server connected_server;
NetworkInfo netInfo;
Cache cache;

View file

@ -15,7 +15,7 @@ int main() {
async::queue_scope qs{&rq};
loop_service service;
Instance instance(service, config);
Instance instance(service, parseConfig("config.inil"));
instance.services.push_back(std::make_unique<TestService>());
async::detach(instance.run());

View file

@ -2,6 +2,8 @@
#include "instance.hpp"
#include <async/result.hpp>
#include <string>
#include <optional>
#include <stdexcept>
@ -11,3 +13,19 @@ async::result<void> ServiceBase::mark_ready(const User& user) {
co_await i->send_event(user.get_euid());
ready = true;
}
std::optional<std::string_view> ServiceBase::getConfig(const std::string& section, const std::string& key) {
auto &cfg = i->config.misc;
// Get section
auto s_res = cfg.find(section);
if (s_res == cfg.end()) {
return {};
}
// Get key
auto k_res = s_res->second.find(key);
if (k_res == s_res->second.end()) {
return {};
}
// Return final result
return {k_res->second};
}

View file

@ -8,6 +8,9 @@ class Instance;
#include "incompletes.hpp"
#include <async/result.hpp>
#include <string>
#include <string_view>
#include <optional>
@ -22,5 +25,6 @@ public:
virtual async::result<void> on_direct_privmsg(std::string_view msg, u_User& author) = 0;
async::result<void> mark_ready(const User& user);
std::optional<std::string_view> getConfig(const std::string& section, const std::string& key);
};
#endif

View file

@ -8,13 +8,10 @@ using fmt::operator""_format;
const auto serviceChannelName = "#servicechannel";
async::result<void> TestService::intitialize() {
co_await i->netInfo.wait_ready();
user = {
.server = i->config.get().server.uid,
.server = i->config.server.uid,
.nick = "services",
.ident = "services",
.realhost = "services.",
@ -23,13 +20,13 @@ async::result<void> TestService::intitialize() {
.loginName = "serviceD"
};
Channel serviceChannel = {
.server = i->config.get().server.uid,
.name = serviceChannelName
.server = i->config.server.uid,
.name = std::string(getConfig("testservice", "channel").value_or("#services"))
};
co_await mark_ready(user);
co_await i->send_event(serviceChannel.get_sjoin(user.uid));
co_await i->send_event(serviceChannel.get_topic("IRC Service channel", user.uid));
co_await i->send_event(user.get_notice("Test... Hello world!", serviceChannelName));
co_await i->send_event(user.get_notice("Test... Hello world!", serviceChannel.name));
}
async::result<void> TestService::on_event(const Event& event) {

View file

@ -23,9 +23,9 @@ std::vector<std::string_view> strSplit(std::string_view s, char delimiter, size_
return to_return;
}
std::tuple<std::string_view, std::string_view> colonSplit(std::string_view s) {
std::tuple<std::string_view, std::string_view> splitOnce(std::string_view s, std::string_view at) {
// Find the colon
auto colonPos = s.find(" :");
auto colonPos = s.find(at);
if (colonPos == s.npos) {
return {s, ""};
}
@ -54,7 +54,7 @@ std::string lowers(std::string_view str) {
static const char UUIDChars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
UUID Instance::UUIDGen() {
size_t numUUID = ++lastUUID;
UUID fres = config.get().server.uid.str();
UUID fres = config.server.uid.str();
for (auto it = fres.array.end() - 1; it != fres.array.begin()+SUID_len-1; it--) {
auto idx = std::min(numUUID, sizeof(UUIDChars)-1);
*it = UUIDChars[idx];

View file

@ -11,7 +11,7 @@ namespace Utility {
constexpr size_t strSplitInf = 0;
std::vector<std::string_view> strSplit(std::string_view s, char delimiter, size_t times = strSplitInf);
std::tuple<std::string_view, std::string_view> colonSplit(std::string_view s);
std::tuple<std::string_view, std::string_view> splitOnce(std::string_view s, std::string_view at);
void argsSizeCheck(std::string_view where, std::vector<std::string_view> args, size_t expected);
std::string lowers(std::string_view str);
}