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

Added simple test service

This commit is contained in:
Nils 2021-06-19 21:48:01 +02:00
parent 98e023743b
commit fadab89638
11 changed files with 238 additions and 28 deletions

View file

@ -9,6 +9,8 @@ add_executable(asbots
main.cpp
instance.cpp
utility.cpp
serviceBase.cpp
services/test.cpp
config.cpp
)

View file

@ -31,7 +31,7 @@ void Event::parse(std::string_view str) {
} else if (id_len == UUID_len) {
sender = UUID(std::move(split[0]));
} else {
sender = std::string(split[0]);
sender = split[0];
}
name = std::move(split[1]);
if (split.size() == 3) {
@ -196,6 +196,13 @@ std::vector<u_Channel>::iterator Cache::find_channel_by_name(std::string_view na
async::result<void> Instance::run() {
// Prepare services
for (auto& service : services) {
service->i = this;
service->uuid = UUIDGen();
async::detach(service->intitialize());
}
// Create connection
socket.reset(new uvpp::tcp{s});
co_await socket->connect(addr);
@ -252,27 +259,16 @@ async::result<void> Instance::login() {
}
async::result<void> Instance::burst() {
User userEUID = {
.server = config.get().server.uid,
.nick = "services",
.ident = "services",
.host = "services.",
.realhost = "127.0.0.1",
.uid = UUIDGen(),
.realname = "LOL"
};
co_await send_event(userEUID.get_euid());
co_await send_event(userEUID.get_join("#lol"));
co_await send_ping();
client_bursting = false;
// Wait for burst to complete
std::cout << "I'm done bursting too. Waiting for network informations..." << std::endl;
co_await socket->send("VERSION\n"sv);
co_await netInfo.wait_ready();
std::cout << "Ready." << std::endl;
co_await send_ping();
client_bursting = false;
}
async::result<void> Instance::process(const Command command) {
std::clog << command.dump() << std::flush;
if (command.name == "PASS") {
// Check password
auto given_password = strSplit(command.args, ' ', 1)[0];
@ -284,6 +280,10 @@ async::result<void> Instance::process(const Command command) {
connected_server.uid = SUID(command.text);
} else if (command.name == "ERROR") {
throw ConnectionError(command.dump());
} else if (command.name == "SQUIT") {
if (command.args == config.get().server.uid.str()) {
throw ConnectionError(command.dump());
}
} else if (!authed) {
throw ConnectionError("Server tried to execute a command before authenticating");
} else if (command.name == "SERVER") {
@ -303,6 +303,7 @@ async::result<void> Instance::process(const Command command) {
}
async::result<void> Instance::process(const Event event) {
std::clog << event.dump() << std::flush;
if (event.name == "NOTICE") {
// Don't do anything special
} else if (!authed) {
@ -473,13 +474,38 @@ async::result<void> Instance::process(const Event event) {
// Apply changes
c_res->get()->mode.parse<true>("+{} {}"_format(modes, event.text), netInfo);
}
// Messages
else if (event.name == "PRIVMSG") {
// On message
// Check that message is not directed to channel
if (isalnum(event.args[0])) {
// Get author from cache
auto res = cache.find_user_by_uid(std::get<UUID>(event.sender.id));
if (res == cache.users.end()) {
throw DesyncError();
}
// Get target UUID
UUID target(event.args);
// Pass to services with ownership over target
for (auto& service : services) {
if (service->ready && service->uuid.str() == target.str()) {
co_await service->on_direct_privmsg(event.text, *res->get());
}
}
}
}
// Pass to services
for (auto& service : services) {
if (service->ready) {
co_await service->on_event(event);
}
}
}
std::clog << event.dump() << std::flush;
}
async::result<void> Instance::send_event(const Event& event) {
co_await socket->send(event.dump());
async::detach(process(event));
co_await process(event);
}
async::result<void> Instance::send_ping() {

View file

@ -1,6 +1,8 @@
#ifndef _INSTANCE_HPP
#define _INSTANCE_HPP
#include "config.hpp"
#include "uid.hpp"
#include "serviceBase.hpp"
#include <uvpp.hpp>
#include <async/result.hpp>
@ -75,6 +77,15 @@ struct Channel {
void parse_sjoin(const Event &event, Cache& cache, NetworkInfo& netInfo);
void removeMember(const u_User& member);
Event get_sjoin(const UUID& initial_user) const {
return {
.sender = SUID(server),
.name = "SJOIN",
.args = fmt::format("{} {} +{}", time(nullptr), name, mode.str),
.text = fmt::format("@{}", initial_user.str())
};
}
};
struct User {
@ -89,6 +100,9 @@ struct User {
std::string realname;
std::vector<std::reference_wrapper<u_Channel>> channels;
void parse_euid(const Event &event, NetworkInfo& netInfo);
void removeChannel(const u_Channel &channel);
Event get_euid() const {
return {
.sender = SUID(server),
@ -103,12 +117,30 @@ struct User {
.args = fmt::format("{} {} +", time(nullptr), channelName)
};
}
auto get_join(const u_Channel channel) const {
return get_join(channel->name);
Event get_part(std::string_view channelName, std::string_view message = "") const {
return {
.sender = uid,
.name = "PART",
.args = std::string(channelName),
.text = std::string(message)
};
}
Event get_quit(std::string_view message = "") const {
return {
.sender = uid,
.name = "QUIT",
.text = std::string(message)
};
}
void parse_euid(const Event &event, NetworkInfo& netInfo);
void removeChannel(const u_Channel &channel);
Event get_privmsg(std::string_view message, AnyUID target) {
return {
.sender = uid,
.name = "PRIVMSG",
.args = std::string(target.str()),
.text = std::string(message)
};
}
};
struct Cache {
@ -164,17 +196,21 @@ struct NetworkInfo {
class Instance {
std::reference_wrapper<uvpp::loop_service> s;
std::reference_wrapper<const Config> config;
uvpp::Addr addr;
std::unique_ptr<uvpp::tcp> socket;
Config::Server connected_server;
NetworkInfo netInfo;
Cache cache;
size_t lastUUID = 0;
bool server_bursting = true, client_bursting = true;
bool authed = false;
public:
std::unique_ptr<uvpp::tcp> socket;
std::reference_wrapper<const Config> config;
Config::Server connected_server;
NetworkInfo netInfo;
Cache cache;
std::vector<std::unique_ptr<ServiceBase>> services;
Instance(uvpp::loop_service &s, const Config& config) : s(s), config(config) {
addr = uvpp::make_ipv4(config.connection.addr, config.connection.port);
}
@ -189,7 +225,6 @@ public:
async::result<void> send_ping();
// utils.cpp
size_t lastUUID = 0;
UUID UUIDGen();
};
#endif

View file

@ -1,6 +1,8 @@
#include "config.hpp"
#include "instance.hpp"
#include "services/test.hpp"
#include <uvpp.hpp>
#include <async/result.hpp>
using namespace std;
@ -14,6 +16,7 @@ int main() {
loop_service service;
Instance instance(service, config);
instance.services.push_back(std::make_unique<TestService>());
async::detach(instance.run());
async::run_forever(rq.run_token(), loop_service_wrapper{service});

13
serviceBase.cpp Normal file
View file

@ -0,0 +1,13 @@
#include "serviceBase.hpp"
#include "instance.hpp"
#include <async/result.hpp>
#include <stdexcept>
async::result<void> ServiceBase::mark_ready(const User& user) {
co_await i->netInfo.wait_ready();
co_await i->send_event(user.get_euid());
ready = true;
}

25
serviceBase.hpp Normal file
View file

@ -0,0 +1,25 @@
#ifndef _SERVICEBASE_HPP
#define _SERVICEBASE_HPP
class Event;
class User;
class Instance;
#include "uid.hpp"
#include <async/result.hpp>
class ServiceBase {
public:
UUID uuid;
Instance *i;
bool ready = false;
virtual async::result<void> intitialize() = 0;
virtual async::result<void> on_event(const Event& event) = 0;
virtual async::result<void> on_direct_privmsg(std::string_view msg, const User& author) = 0;
async::result<void> mark_ready(const User& user);
};
#endif

28
services/template.cpp Normal file
View file

@ -0,0 +1,28 @@
#include "test.hpp"
#include <async/result.hpp>
async::result<void> TestService::intitialize() {
user = {
.server = i->config.get().server.uid,
.nick = "services",
.ident = "services",
.host = "services.",
.realhost = "127.0.0.1",
.uid = uuid,
.realname = "LOL"
};
co_await mark_ready(user);
co_await i->send_event(user.get_join("#lol"));
co_await i->send_event(user.get_privmsg("Test... Hello world!", "#lol"));
}
async::result<void> TestService::on_event(const Event& event) {
co_return;
}
async::result<void> TestService::on_direct_privmsg(std::string_view msg, const User& author) {
co_await i->send_event(user.get_privmsg("I received a message: "+std::string(msg), "#lol"));
}

17
services/template.hpp Normal file
View file

@ -0,0 +1,17 @@
#ifndef _TEST_HPP
#define _TEST_HPP
#include "../instance.hpp"
#include "../serviceBase.hpp"
#include <async/result.hpp>
class TestService : public ServiceBase {
User user;
virtual async::result<void> intitialize() override;
virtual async::result<void> on_event(const Event& event) override;
virtual async::result<void> on_direct_privmsg(std::string_view msg, const User& author) override;
};
#endif

40
services/test.cpp Normal file
View file

@ -0,0 +1,40 @@
#include "test.hpp"
#include <async/result.hpp>
#include <fmt/format.h>
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,
.nick = "services",
.ident = "services",
.host = "services.",
.realhost = "127.0.0.1",
.uid = uuid,
.realname = i->netInfo.name
};
Channel serviceChannel = {
.server = i->config.get().server.uid,
.name = serviceChannelName
};
co_await mark_ready(user);
co_await i->send_event(serviceChannel.get_sjoin(uuid));
co_await i->send_event(user.get_join(serviceChannelName));
co_await i->send_event(user.get_privmsg("Test... Hello world!", serviceChannelName));
}
async::result<void> TestService::on_event(const Event& event) {
co_return;
}
async::result<void> TestService::on_direct_privmsg(std::string_view msg, const User& author) {
co_await i->send_event(user.get_privmsg("I received a message from {}: {}"_format(author.nick, msg), serviceChannelName));
}

17
services/test.hpp Normal file
View file

@ -0,0 +1,17 @@
#ifndef _TEST_HPP
#define _TEST_HPP
#include "../instance.hpp"
#include "../serviceBase.hpp"
#include <async/result.hpp>
class TestService : public ServiceBase {
User user;
virtual async::result<void> intitialize() override;
virtual async::result<void> on_event(const Event& event) override;
virtual async::result<void> on_direct_privmsg(std::string_view msg, const User& author) override;
};
#endif

View file

@ -78,7 +78,11 @@ struct AnyUID {
type = USER;
id = val;
}
auto operator =(const std::string& val) {
auto operator =(std::string_view val) {
type = OTHER;
id = std::string(val);
}
auto operator =(const char *val) {
type = OTHER;
id = std::string(val);
}