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:
parent
98e023743b
commit
fadab89638
11 changed files with 238 additions and 28 deletions
|
@ -9,6 +9,8 @@ add_executable(asbots
|
|||
main.cpp
|
||||
instance.cpp
|
||||
utility.cpp
|
||||
serviceBase.cpp
|
||||
services/test.cpp
|
||||
config.cpp
|
||||
)
|
||||
|
||||
|
|
60
instance.cpp
60
instance.cpp
|
@ -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() {
|
||||
|
|
55
instance.hpp
55
instance.hpp
|
@ -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
|
||||
|
|
3
main.cpp
3
main.cpp
|
@ -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
13
serviceBase.cpp
Normal 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
25
serviceBase.hpp
Normal 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
28
services/template.cpp
Normal 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
17
services/template.hpp
Normal 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
40
services/test.cpp
Normal 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
17
services/test.hpp
Normal 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
|
6
uid.hpp
6
uid.hpp
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue