From fadab896383dd611a808e8cd460db62a4b9b5583 Mon Sep 17 00:00:00 2001 From: Nils Date: Sat, 19 Jun 2021 21:48:01 +0200 Subject: [PATCH] Added simple test service --- CMakeLists.txt | 2 ++ instance.cpp | 60 +++++++++++++++++++++++++++++++------------ instance.hpp | 55 +++++++++++++++++++++++++++++++-------- main.cpp | 3 +++ serviceBase.cpp | 13 ++++++++++ serviceBase.hpp | 25 ++++++++++++++++++ services/template.cpp | 28 ++++++++++++++++++++ services/template.hpp | 17 ++++++++++++ services/test.cpp | 40 +++++++++++++++++++++++++++++ services/test.hpp | 17 ++++++++++++ uid.hpp | 6 ++++- 11 files changed, 238 insertions(+), 28 deletions(-) create mode 100644 serviceBase.cpp create mode 100644 serviceBase.hpp create mode 100644 services/template.cpp create mode 100644 services/template.hpp create mode 100644 services/test.cpp create mode 100644 services/test.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d1b968a..6976f1c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,8 @@ add_executable(asbots main.cpp instance.cpp utility.cpp + serviceBase.cpp + services/test.cpp config.cpp ) diff --git a/instance.cpp b/instance.cpp index 81438fc..4c12b4e 100644 --- a/instance.cpp +++ b/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::iterator Cache::find_channel_by_name(std::string_view na async::result 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 Instance::login() { } async::result 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 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 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 Instance::process(const Command command) { } async::result 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 Instance::process(const Event event) { // Apply changes c_res->get()->mode.parse("+{} {}"_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(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 Instance::send_event(const Event& event) { co_await socket->send(event.dump()); - async::detach(process(event)); + co_await process(event); } async::result Instance::send_ping() { diff --git a/instance.hpp b/instance.hpp index 60fe4f5..03d1905 100644 --- a/instance.hpp +++ b/instance.hpp @@ -1,6 +1,8 @@ #ifndef _INSTANCE_HPP #define _INSTANCE_HPP #include "config.hpp" +#include "uid.hpp" +#include "serviceBase.hpp" #include #include @@ -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> 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 s; - std::reference_wrapper config; uvpp::Addr addr; - std::unique_ptr 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 socket; + std::reference_wrapper config; + Config::Server connected_server; + NetworkInfo netInfo; + Cache cache; + + std::vector> 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 send_ping(); // utils.cpp - size_t lastUUID = 0; UUID UUIDGen(); }; #endif diff --git a/main.cpp b/main.cpp index 88cee14..42a2a9f 100644 --- a/main.cpp +++ b/main.cpp @@ -1,6 +1,8 @@ #include "config.hpp" #include "instance.hpp" +#include "services/test.hpp" + #include #include using namespace std; @@ -14,6 +16,7 @@ int main() { loop_service service; Instance instance(service, config); + instance.services.push_back(std::make_unique()); async::detach(instance.run()); async::run_forever(rq.run_token(), loop_service_wrapper{service}); diff --git a/serviceBase.cpp b/serviceBase.cpp new file mode 100644 index 0000000..f8252cf --- /dev/null +++ b/serviceBase.cpp @@ -0,0 +1,13 @@ +#include "serviceBase.hpp" +#include "instance.hpp" + +#include +#include + + + +async::result ServiceBase::mark_ready(const User& user) { + co_await i->netInfo.wait_ready(); + co_await i->send_event(user.get_euid()); + ready = true; +} diff --git a/serviceBase.hpp b/serviceBase.hpp new file mode 100644 index 0000000..004690a --- /dev/null +++ b/serviceBase.hpp @@ -0,0 +1,25 @@ +#ifndef _SERVICEBASE_HPP +#define _SERVICEBASE_HPP +class Event; +class User; +class Instance; + +#include "uid.hpp" + +#include + + + +class ServiceBase { +public: + UUID uuid; + Instance *i; + bool ready = false; + + virtual async::result intitialize() = 0; + virtual async::result on_event(const Event& event) = 0; + virtual async::result on_direct_privmsg(std::string_view msg, const User& author) = 0; + + async::result mark_ready(const User& user); +}; +#endif diff --git a/services/template.cpp b/services/template.cpp new file mode 100644 index 0000000..2573744 --- /dev/null +++ b/services/template.cpp @@ -0,0 +1,28 @@ +#include "test.hpp" + +#include + + + +async::result 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 TestService::on_event(const Event& event) { + co_return; +} + +async::result 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")); +} diff --git a/services/template.hpp b/services/template.hpp new file mode 100644 index 0000000..d436ca9 --- /dev/null +++ b/services/template.hpp @@ -0,0 +1,17 @@ +#ifndef _TEST_HPP +#define _TEST_HPP +#include "../instance.hpp" +#include "../serviceBase.hpp" + +#include + + + +class TestService : public ServiceBase { + User user; + + virtual async::result intitialize() override; + virtual async::result on_event(const Event& event) override; + virtual async::result on_direct_privmsg(std::string_view msg, const User& author) override; +}; +#endif diff --git a/services/test.cpp b/services/test.cpp new file mode 100644 index 0000000..e15139d --- /dev/null +++ b/services/test.cpp @@ -0,0 +1,40 @@ +#include "test.hpp" + +#include +#include + +using fmt::operator""_format; + + + +const auto serviceChannelName = "#servicechannel"; + + +async::result 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 TestService::on_event(const Event& event) { + co_return; +} + +async::result 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)); +} diff --git a/services/test.hpp b/services/test.hpp new file mode 100644 index 0000000..d436ca9 --- /dev/null +++ b/services/test.hpp @@ -0,0 +1,17 @@ +#ifndef _TEST_HPP +#define _TEST_HPP +#include "../instance.hpp" +#include "../serviceBase.hpp" + +#include + + + +class TestService : public ServiceBase { + User user; + + virtual async::result intitialize() override; + virtual async::result on_event(const Event& event) override; + virtual async::result on_direct_privmsg(std::string_view msg, const User& author) override; +}; +#endif diff --git a/uid.hpp b/uid.hpp index 39778e2..43aa7e9 100644 --- a/uid.hpp +++ b/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); }