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

Even more improvements lol

This commit is contained in:
Nils 2021-06-21 00:29:37 +02:00
parent d2f38b272b
commit 315b65f0c3
9 changed files with 178 additions and 85 deletions

21
exceptions.hpp Normal file
View file

@ -0,0 +1,21 @@
#ifndef __EXCEPTIONS_HPP
#define __EXCEPTIONS_HPP
#include <stdexcept>
struct ParseError : public std::runtime_error {
using std::runtime_error::runtime_error;
};
struct ConnectionError : public std::runtime_error {
using std::runtime_error::runtime_error;
};
struct DesyncError : public std::exception {
const char *what() const throw() {
return "Server has desynced!!!";
}
DesyncError() {
std::cout << "DESCONACCREKO" << std::endl;
}
};
#endif

13
incompletes.hpp Normal file
View file

@ -0,0 +1,13 @@
#ifndef _INCOMPLETES_HPP
#define _INCOMPLETES_HPP
#include <memory>
struct User;
struct Channel;
struct Cache;
struct NetworkInfo;
using u_User = std::unique_ptr<User>;
using u_Channel = std::unique_ptr<Channel>;
#endif

View file

@ -36,7 +36,7 @@ void Event::parse(std::string_view str) {
name = std::move(split[1]);
if (split.size() == 3) {
// Get args and text
std::tie(args, text) = colonSplit(split[2]);
std::tie(raw_args, text) = colonSplit(split[2]);
}
}
@ -112,19 +112,22 @@ void ModeSet::parse(std::string_view in, NetworkInfo &netInfo) {
void User::parse_euid(const Event& event, NetworkInfo& netInfo) {
this->server = std::get<SUID>(event.sender.id);
auto split = strSplit(event.args, ' ', 8);
// Check size
if (split.size() != 9) {
if (event.args.size() < 10) {
throw ParseError("In euid parser: This euid event does not have enough arguments");
}
// Move values
nick = std::move(split[0]);
hops = std::stoull(std::string(split[1]));
umode.parse<false>(split[3], netInfo);
ident = std::move(split[4]);
host = std::move(split[5]);
realhost = std::move(split[6]);
uid = UUID(std::move(split[7]));
nick = event.args[0];
hops = std::stoull(std::string(event.args[1]));
umode.parse<false>(event.args[3], netInfo);
ident = event.args[4];
vhost = event.args[5];
ip = event.args[6];
uid = UUID(event.args[7]);
realhost = event.args[8];
if (event.args[9] != "*" && event.args[9] != "0") {
loginName = event.args[9];
}
// Get realname
realname = std::move(event.text);
}
@ -136,14 +139,13 @@ void User::removeChannel(const u_Channel& channel) {
void Channel::parse_sjoin(const Event& event, Cache& cache, NetworkInfo& netInfo) {
this->server = std::get<SUID>(event.sender.id);
auto split = strSplit(event.args, ' ', 2);
// Check size
if (split.size() != 3) {
if (event.args.size() < 3) {
throw ParseError("In euid parser: This euid event does not have enough arguments");
}
// Move values
name = std::move(split[1]);
mode.parse<true>(split[2], netInfo);
name = std::move(event.args[1]);
mode.parse<true>(event.args[2], netInfo);
// Get members
for (auto& raw_uuid : strSplit(event.text, ' ')) {
// Erase prefix
@ -302,23 +304,21 @@ async::result<void> Instance::process(const Command command) {
}
}
async::result<void> Instance::process(const Event event) {
async::result<void> Instance::process(Event event) {
event.splitArgs();
std::clog << event.dump() << std::flush;
if (event.name == "NOTICE") {
// Don't do anything special
} else if (!authed) {
if (!authed && event.name != "NOTICE") {
throw ConnectionError("Server tried to send an event before authenticating");
}
// Fetched info
else if (event.name == "005") {
// Check if that 005 was for me
if (event.args.find(config.get().server.uid.str()) != 0) {
if (event.args[0] != config.get().server.uid.str()) {
co_return;
}
// Split the list
auto split = strSplit(event.args, ' ');
// Iterate and find the information we need
for (const auto& field : split) {
for (const auto& field : event.args) {
// Split into key and value
auto split = strSplit(field, '=', 1);
// Check size
@ -389,7 +389,7 @@ async::result<void> Instance::process(const Event event) {
throw DesyncError();
}
// Set nick
res->get()->nick = strSplit(event.args, ' ', 1)[0];
res->get()->nick = event.args[0];
} else if (event.name == "MODE") {
// User changed their mode
// Find user in cache
@ -399,6 +399,34 @@ async::result<void> Instance::process(const Event event) {
}
// Update mode
res->get()->umode.parse<false>(event.text, netInfo);
} else if (event.name == "ENCAP") {
// Get args
if (event.args.size() < 3) {
throw ParseError("In encap event parser: at least * and encap name need to be passed");
}
if (event.args[1] == "SU") {
// User logged in
// Check args
if (event.args.size() < 5) {
throw ParseError("In encap su event parser: this encap requires UID as first argument and optionally login name as second one");
}
// Find user in cache
auto res = cache.find_user_by_uid(event.args[2]);
if (res == cache.users.end()) {
throw DesyncError();
}
// Update login name
if (event.args.size() > 3) {
auto loginName = event.args[3];
if (loginName == "*" || loginName == "0") {
res->get()->loginName.reset();
} else {
res->get()->loginName = event.args[3];
}
} else {
res->get()->loginName.reset();
}
}
}
// Channel updates
else if (event.name == "SJOIN") {
@ -411,7 +439,7 @@ async::result<void> Instance::process(const Event event) {
} else if (event.name == "TOPIC" || event.name == "TB") {
// Channels topic changed
// Find channel in cache
auto res = cache.find_channel_by_name(strSplit(event.args, ' ', 1)[0]);
auto res = cache.find_channel_by_name(event.args[0]);
if (res == cache.channels.end()) {
throw DesyncError();
}
@ -420,12 +448,11 @@ async::result<void> Instance::process(const Event event) {
} else if (event.name == "JOIN") {
// User joined existing channel
// Split args
auto split = strSplit(event.args, ' ', 2);
if (split.size() != 3) {
if (event.args.size() < 3) {
throw ParseError("In join event parser: join even did not receive enough arguments (expected 3)");
}
// Get channel from cache
auto c_res = cache.find_channel_by_name(split[1]);
auto c_res = cache.find_channel_by_name(event.args[1]);
if (c_res == cache.channels.end()) {
throw DesyncError();
}
@ -438,17 +465,16 @@ async::result<void> Instance::process(const Event event) {
c_res->get()->members.push_back(&*u_res);
u_res->get()->channels.push_back(&*c_res);
// Update channel modes
c_res->get()->mode.parse<true>(split[2], netInfo);
c_res->get()->mode.parse<true>(event.args[2], netInfo);
} else if (event.name == "PART" || event.name == "KICK") {
// User left channel
auto split = strSplit(event.args, ' ', 1);
// Get channel from cache
auto c_res = cache.find_channel_by_name(split[0]);
auto c_res = cache.find_channel_by_name(event.args[0]);
if (c_res == cache.channels.end()) {
throw DesyncError();
}
// Get user from cache
auto u_res = cache.find_user_by_uid((event.name=="PART")?std::get<UUID>(event.sender.id):split[1]);
auto u_res = cache.find_user_by_uid((event.name=="PART")?std::get<UUID>(event.sender.id):event.args[1]);
if (u_res == cache.users.end()) {
throw DesyncError();
}
@ -460,12 +486,11 @@ async::result<void> Instance::process(const Event event) {
// Split args
std::string_view modes, channelName;
{
auto split = strSplit(event.args, ' ', 2);
if (split.size() != 3) {
throw DesyncError();
if (event.args.size() < 3) {
throw ParseError("In MODE/BMASK event parser: did not receive enough arguments (expected 3)");
}
channelName = split[1];
modes = split[2];
channelName = event.args[1];
modes = event.args[2];
}
// Get channel from cache
auto c_res = cache.find_channel_by_name(channelName);
@ -479,18 +504,18 @@ async::result<void> Instance::process(const Event event) {
else if (event.name == "PRIVMSG") {
// On message
// Check that message is not directed to channel
if (isalnum(event.args[0])) {
if (isalnum(event.raw_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);
UUID target(event.args[0]);
// 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());
co_await service->on_direct_privmsg(event.text, *res);
}
}
}

View file

@ -3,6 +3,9 @@
#include "config.hpp"
#include "uid.hpp"
#include "serviceBase.hpp"
#include "utility.hpp"
#include "incompletes.hpp"
#include "exceptions.hpp"
#include <uvpp.hpp>
#include <async/result.hpp>
@ -11,44 +14,26 @@
#include <fmt/format.h>
#include <string>
#include <string_view>
#include <optional>
#include <unordered_map>
#include <vector>
#include <memory>
#include <stdexcept>
#include <ctime>
struct ParseError : public std::runtime_error {
using std::runtime_error::runtime_error;
};
struct ConnectionError : public std::runtime_error {
using std::runtime_error::runtime_error;
};
struct DesyncError : public std::exception {
const char *what() const throw() {
return "Server has desynced!!!";
}
DesyncError() {
std::cout << "DESCONACCREKO" << std::endl;
}
};
struct User;
struct Channel;
struct Cache;
struct NetworkInfo;
using u_User = std::unique_ptr<User>;
using u_Channel = std::unique_ptr<Channel>;
struct Event {
struct Event { // DON'T std::move() this class. EVER!!!
AnyUID sender;
std::string name, args, text;
std::string name, raw_args, text;
std::vector<std::string_view> args;
std::string dump() const {
return fmt::format(":{} {} {}{}\n", sender.str(), name, args, (text.empty()?"":" :"+text));
return fmt::format(":{} {} {}{}\n", sender.str(), name, raw_args, (text.empty()?"":" :"+text));
}
void parse(std::string_view str);
void splitArgs() {
args = Utility::strSplit(raw_args, ' ');
}
};
struct Command {
@ -82,10 +67,18 @@ struct Channel {
return {
.sender = SUID(server),
.name = "SJOIN",
.args = fmt::format("{} {} +{}", time(nullptr), name, mode.str),
.raw_args = fmt::format("{} {} +{}", time(nullptr), name, mode.str),
.text = fmt::format("@{}", initial_user.str())
};
}
Event get_topic(std::string_view topic, const UUID& user) const {
return {
.sender = user,
.name = "TOPIC",
.raw_args = name,
.text = std::string(topic)
};
}
};
struct User {
@ -94,11 +87,13 @@ struct User {
size_t hops = 1;
ModeSet umode;
std::string ident;
std::string host;
std::optional<std::string> vhost;
std::optional<std::string> ip;
std::string realhost;
UUID uid;
std::string realname;
std::vector<u_Channel*> channels;
std::optional<std::string> loginName;
void parse_euid(const Event &event, NetworkInfo& netInfo);
void removeChannel(const u_Channel &channel);
@ -107,21 +102,32 @@ struct User {
return {
.sender = SUID(server),
.name = "EUID",
.args = fmt::format("{} 1 {} +{} {} {} 0 {} * * :{}", nick, time(nullptr), umode.str, ident, host, uid.str(), realname)
// nick
// | hops
// | | ts
// | | | umode
// | | | | ident
// | | | | | vhost
// | | | | | | ip
// | | | | | | | uid
// | | | | | | | | realhost
// | | | | | | | | | account
// | | | | | | | | | | realname
.raw_args = fmt::format("{} 1 {} +{} {} {} {} {} {} {} :{}", nick, time(nullptr), umode.str, ident, vhost.value_or(realhost), ip.value_or("*"), uid.str(), realhost, loginName.value_or("*"), realname)
};
}
Event get_join(std::string_view channelName) const {
return {
.sender = uid,
.name = "JOIN",
.args = fmt::format("{} {} +", time(nullptr), channelName)
.raw_args = fmt::format("{} {} +", time(nullptr), channelName)
};
}
Event get_part(std::string_view channelName, std::string_view message = "") const {
return {
.sender = uid,
.name = "PART",
.args = std::string(channelName),
.raw_args = std::string(channelName),
.text = std::string(message)
};
}
@ -133,19 +139,28 @@ struct User {
};
}
Event get_privmsg(std::string_view message, AnyUID target) {
Event get_encap_su(std::string_view login_name) {
//:<my_sid> ENCAP * SU <user_uid> <new_account_name>
return {
.sender = server,
.name = "ENCAP",
.raw_args = fmt::format("* SU {} {}", uid.str(), login_name)
};
}
Event get_privmsg(std::string_view message, AnyUID target) const {
return {
.sender = uid,
.name = "PRIVMSG",
.args = std::string(target.str()),
.raw_args = std::string(target.str()),
.text = std::string(message)
};
}
Event get_notice(std::string_view message, AnyUID target) {
Event get_notice(std::string_view message, AnyUID target) const {
return {
.sender = uid,
.name = "NOTICE",
.args = std::string(target.str()),
.raw_args = std::string(target.str()),
.text = std::string(message)
};
}
@ -227,7 +242,7 @@ public:
async::result<void> login();
async::result<void> burst();
async::result<void> process(const Command);
async::result<void> process(const Event);
async::result<void> process(Event);
async::result<void> send_event(const Event&);
async::result<void> send_ping();

View file

@ -5,6 +5,7 @@ class User;
class Instance;
#include "uid.hpp"
#include "incompletes.hpp"
#include <async/result.hpp>
@ -18,7 +19,7 @@ public:
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;
virtual async::result<void> on_direct_privmsg(std::string_view msg, u_User& author) = 0;
async::result<void> mark_ready(const User& user);
};

View file

@ -23,6 +23,6 @@ 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) {
async::result<void> TestService::on_direct_privmsg(std::string_view msg, u_User& author) {
co_await i->send_event(user.get_privmsg("I received a message: "+std::string(msg), "#lol"));
}

View file

@ -12,6 +12,6 @@ class TestService : public ServiceBase {
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;
virtual async::result<void> on_direct_privmsg(std::string_view msg, u_User& author) override;
};
#endif

View file

@ -1,4 +1,5 @@
#include "test.hpp"
#include "../utility.hpp"
#include <async/result.hpp>
#include <fmt/format.h>
@ -16,18 +17,19 @@ async::result<void> TestService::intitialize() {
.server = i->config.get().server.uid,
.nick = "services",
.ident = "services",
.host = "services.",
.realhost = "127.0.0.1",
.realhost = "services.",
.uid = uuid,
.realname = i->netInfo.name
.realname = i->netInfo.name,
.loginName = "serviceD"
};
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(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_encap_su("serviceD")); DOES NOT YET WORK!!
co_await i->send_event(user.get_notice("Test... Hello world!", serviceChannelName));
}
@ -35,6 +37,22 @@ 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));
async::result<void> TestService::on_direct_privmsg(std::string_view msg, u_User &author) {
auto cmd = Utility::strSplit(msg, ' ', 1);
Event response = user.get_notice("You need to log in first", author->uid);
if (cmd[0] == "SEND") {
if (author->loginName.value_or("") == "NetOP") {
Event event;
try {
event.parse(cmd[1]);
co_await i->send_event(event);
response = user.get_notice("Sent.", author->uid);
} catch (std::exception&e) {
response = user.get_notice(e.what(), author->uid);
}
}
} else {
response = user.get_notice("Unknown command", author->uid);
}
co_await i->send_event(response);
}

View file

@ -12,6 +12,6 @@ class TestService : public ServiceBase {
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;
virtual async::result<void> on_direct_privmsg(std::string_view msg, u_User& author) override;
};
#endif