#pragma once #include "json.hpp" #include #include namespace sliger::rpc { struct Err { std::string msg; }; template class Res { public: Res(T value) : holds_value(true) , value(std::move(value)) { } Res(Err error) : holds_value(false) , error(error) { } auto is_ok() -> bool { return this->holds_value; } auto ok() & -> T& { return this->value; } auto ok() && -> T&& { return std::move(this->value); } auto err() -> Err { return this->error; } private: bool holds_value; T value; Err error; }; template <> class Res { public: Res() : holds_value(true) { } Res(Err error) : holds_value(false) , error(error) { } auto is_ok() -> bool { return this->holds_value; } auto err() -> Err { return this->error; } private: bool holds_value; Err error; }; class BracketFinder { public: BracketFinder() : layers(0) { } auto feed(int8_t c) { if (c == '{') { this->layers += 1; } else if (c == '}') { this->layers -= 1; } } auto bracket_closed() -> bool { return this->layers == 0; } private: int layers; }; #define DONT_COPY_OR_MOVE(T) \ T(const T&) = delete; \ T operator=(const T&) = delete; \ T(T&&) = delete; \ T operator=(T&&) = delete; class Client; class Socket { public: DONT_COPY_OR_MOVE(Socket); Socket() = default; ~Socket() { if (this->initialized) { close(this->socket_fd); } } auto init() -> Res; auto accept() -> Res>; private: int socket_fd = 0; bool initialized = false; }; class Client { public: DONT_COPY_OR_MOVE(Client); Client(int client_sock) : client_sock(client_sock) { } ~Client() { close(client_sock); } auto read(int8_t* buffer, size_t buffer_size) -> ssize_t; auto write(uint8_t* buffer, size_t buffer_size) -> ssize_t; void flush(); private: int client_sock; }; class BufferedWriter { public: BufferedWriter(Client& client) : client(&client) { } auto flush() -> Res; auto write(uint8_t byte) -> Res; auto write(std::string message) -> Res; private: static const size_t length = 1024; size_t occupied = 0; uint8_t buffer[length]; Client* client; }; /// - load code /// - program input /// - run /// - run debug /// - fwamegwaph option /// - code covewage option /// - fetch fwamegwaph /// - json string /// - fetch code covewage /// - json string /// - fetch stack /// - json string template class RpcServer { public: RpcServer(Functor&& functor) : functor(functor) { }; auto listen() -> Res { auto socket = Socket(); if (auto res = socket.init(); not res.is_ok()) { return res.err(); } while (true) { auto client_res = socket.accept(); if (!client_res.is_ok()) { return client_res.err(); } auto client = std::move(client_res.ok()); const size_t buf_len = 1024; int8_t buffer[buf_len] = {}; auto bracket_finder = BracketFinder(); std::string message = {}; while (true) { ssize_t bytes_read = client->read(buffer, buf_len); if (bytes_read <= 0) { break; } for (size_t i = 0; i < (size_t)bytes_read; ++i) { message += buffer[i]; bracket_finder.feed(buffer[i]); if (!bracket_finder.bracket_closed()) { continue; } auto req = sliger::json::parse_json(message); if (!req.ok()) { auto err = req.err(); auto msg = std::format( "error parsing rpc message: '{}' @ {}:{}\n", err.msg, err.pos.line, err.pos.col); return Err { .msg = msg, }; } auto writer = std::make_unique(*client); this->functor(std::move(req.val()), std::move(writer)); message.clear(); goto message_done; } } message_done: } std::unreachable(); }; private: Functor functor; }; };