mirror of
https://gitlab.com/niansa/asbots.git
synced 2025-03-06 20:48:25 +01:00
179 lines
4.9 KiB
C++
179 lines
4.9 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 <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 {
|
|
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
|
|
std::unordered_map<char, char> 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<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
|