#pragma once #include "misc/FileDescriptor.hpp" #include "misc/memory.hpp" #include #include #include #include #include #include #include #include namespace LibSock { namespace Client { struct SRecvData { std::string data; const size_t size = 1024; bool good = false; bool isEmpty() const; void sanitize(); static constexpr char asciiEscape = 0x1B; //  }; enum eEventType : std::uint8_t { READ, WRITE }; class Client { public: Client(bool track = false, bool oneShot = true); ~Client(); const std::string &getName() const; const std::string &getIp() const; bool isAdmin() const; UP read(std::optional> cb = std::nullopt); UP read(const std::string &msg, std::optional> cb = std::nullopt); bool write(const std::string &msg, std::optional> cb = std::nullopt); template bool write(std::format_string fmt, Args &&...args); void run(); bool isValid(); private: WP self; SP m_sockfd; sockaddr_in m_addr; socklen_t m_addrLen = sizeof(m_addr); std::string m_name; std::string m_ip; int m_port; bool m_track; bool m_oneShot; std::optional m_szReading = std::nullopt; void recvLoop(); friend class Clients; }; struct SData { std::string msg; std::optional> sender = std::nullopt; bool admin = false; }; class Clients { public: Clients(); ~Clients(); void newClient(std::optional> cb = std::nullopt); void run(std::optional> cb = std::nullopt); void broadcast(const std::string &msg, std::optional> self = std::nullopt); // second param only specified when we want to exclude the sender void kick(WP client, const bool kill = false, const std::string &reason = ""); void addClient(const Client &client); bool nameExists(const std::string &name); void shutdownClients(); SP getByName(const std::string &name) const; SP getByIp(const std::string &ip) const; std::vector> getClients() const; std::vector getDatas() const; private: void broadcast(const SData &msg); std::vector>> m_vClients; std::vector m_vDatas; }; inline SP pClients; } // namespace Client } // namespace LibSock