#ifndef _INSTANCE_HPP #define _INSTANCE_HPP #include "config.hpp" #include "uid.hpp" #include "serviceBase.hpp" #include #include #include #include #include #include #include #include #include #include #include #include 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; using u_Channel = std::unique_ptr; 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> params; template void parse(std::string_view str, NetworkInfo& netInfo); }; struct Channel { SUID server; std::string name; ModeSet mode; std::string topic; std::vector members; 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 { SUID server; std::string nick; size_t hops = 1; ModeSet umode; std::string ident; std::string host; std::string realhost; UUID uid; 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), .name = "EUID", .args = fmt::format("{} 1 {} +{} {} {} 0 {} * * :{}", nick, time(nullptr), umode.str, ident, host, uid.str(), realname) }; } Event get_join(std::string_view channelName) const { return { .sender = uid, .name = "JOIN", .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), .text = std::string(message) }; } Event get_quit(std::string_view message = "") const { return { .sender = uid, .name = "QUIT", .text = std::string(message) }; } Event get_privmsg(std::string_view message, AnyUID target) { return { .sender = uid, .name = "PRIVMSG", .args = std::string(target.str()), .text = std::string(message) }; } Event get_notice(std::string_view message, AnyUID target) { return { .sender = uid, .name = "NOTICE", .args = std::string(target.str()), .text = std::string(message) }; } }; struct Cache { std::vector users; std::vector channels; std::vector::iterator find_user_by_nick(std::string_view nick); std::vector::iterator find_user_by_uid(const UUID& uid); std::vector::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 std::unordered_map prefixMap; // Maps for example '@' to 'o' bool isListMode(char mode) { return listModes.find(mode) != std::string::npos; } bool takesNoParam(char mode) { return paramLessModes.find(mode) != paramLessModes.npos; } bool takesParamOnUnset(char mode) { return isListMode(mode) || paramOnSetAndUnsetModes.find(mode) != std::string::npos; } bool takesParamOnSet(char mode) { return paramOnSetOnlyModes.find(mode) != std::string::npos || takesParamOnUnset(mode); } } channelModes; async::result wait_ready() { if (!ready) { co_await ready_event.wait(); } } void mark_ready() { ready = true; ready_event.raise(); } }; class Instance { std::reference_wrapper s; uvpp::Addr addr; 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); } async::result run(); async::result login(); async::result burst(); async::result process(const Command); async::result process(const Event); async::result send_event(const Event&); async::result send_ping(); // utils.cpp UUID UUIDGen(); }; #endif