1
0
Fork 0
mirror of https://gitlab.com/niansa/asbots.git synced 2025-03-06 20:48:25 +01:00
asbots/instance.hpp
2021-06-19 14:27:15 +02:00

174 lines
4.7 KiB
C++

#ifndef _INSTANCE_HPP
#define _INSTANCE_HPP
#include "config.hpp"
#include <uvpp.hpp>
#include <async/result.hpp>
#include <async/oneshot-event.hpp>
#include <frg/std_compat.hpp>
#include <fmt/format.h>
#include <string>
#include <string_view>
#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 {
AnyUID sender;
std::string name, args, text;
std::string dump() const {
return fmt::format(":{} {} {}{}\n", sender.str(), name, args, (text.empty()?"":" :"+text));
}
void parse(std::string_view str);
};
struct Command {
std::string name, args, text;
std::string dump() const {
return fmt::format("{} {}{}\n", name, args, (text.empty()?"":" :"+text));
}
void parse(std::string_view str);
};
struct ModeSet {
std::string str;
std::vector<std::tuple<char, std::string>> params;
template<bool channelModes>
void parse(std::string_view str, NetworkInfo& netInfo);
};
struct User {
SUID server;
std::string nick;
size_t hops;
ModeSet umode;
std::string ident;
std::string host;
std::string realhost;
UUID uid;
std::string realname;
std::vector<std::reference_wrapper<u_Channel>> channels;
Event dump() const {
return Event{
.sender = SUID(server),
.name = "EUID",
.args = fmt::format("{} 1 {} {} {} {} 0 {} * * :{}", nick, time(nullptr), umode.str, ident, host, uid.str(), realname)
};
}
void parse_euid(const Event &event, NetworkInfo& netInfo);
void removeChannel(const u_Channel &channel);
};
struct Channel {
SUID server;
std::string name;
ModeSet mode;
std::string topic;
std::vector<std::reference_wrapper<u_User>> members;
void parse_sjoin(const Event &event, Cache& cache, NetworkInfo& netInfo);
void removeMember(const u_User& member);
};
struct Cache {
std::vector<u_User> users;
std::vector<u_Channel> channels;
std::vector<u_User>::iterator find_user_by_nick(std::string_view nick);
std::vector<u_User>::iterator find_user_by_uid(const UUID& uid);
std::vector<u_Channel>::iterator find_channel_by_name(std::string_view name);
};
struct NetworkInfo {
async::oneshot_event ready_event;
size_t fields_received = 0;
bool ready = false;
std::string name;
struct {
// list modes first, then modes that take a param when setting but not when unsetting (just +k), then modes that can only be set once and take args, then modes that can only be set once but take no args.
std::string listModes, // Lists like mode b
paramOnSetAndUnsetModes, // Properties like k
paramOnSetOnlyModes, // Properties like f
paramLessModes; // Properties like z
bool takesNoParam(char mode) {
return paramLessModes.find(mode) != paramLessModes.npos;
}
bool takesParamOnUnset(char mode) {
return listModes.find(mode) != std::string::npos ||
paramOnSetAndUnsetModes.find(mode) != std::string::npos;
}
bool takesParamOnSet(char mode) {
return paramOnSetOnlyModes.find(mode) != std::string::npos ||
takesParamOnUnset(mode);
}
} channelModes;
async::result<void> wait_ready() {
if (!ready) {
co_await ready_event.wait();
}
}
void mark_ready() {
ready = true;
ready_event.raise();
}
};
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;
bool server_bursting = true, client_bursting = true;
bool authed = false;
public:
Instance(uvpp::loop_service &s, const Config& config) : s(s), config(config) {
addr = uvpp::make_ipv4(config.connection.addr, config.connection.port);
}
async::result<void> run();
async::result<void> login();
async::result<void> burst();
async::result<void> process(const Command);
async::result<void> process(const Event);
async::result<void> send_ping();
};
#endif