mirror of
https://git.sfja.dk/Mikkel/slige.git
synced 2025-01-18 19:16:35 +00:00
211 lines
4.8 KiB
C++
211 lines
4.8 KiB
C++
#pragma once
|
|
|
|
#include "json.hpp"
|
|
#include <format>
|
|
#include <iostream>
|
|
|
|
namespace sliger::rpc {
|
|
|
|
struct Err {
|
|
std::string msg;
|
|
};
|
|
|
|
template <typename T> 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<void> {
|
|
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<void>;
|
|
auto accept() -> Res<std::unique_ptr<Client>>;
|
|
|
|
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<size_t>;
|
|
auto write(uint8_t byte) -> Res<void>;
|
|
auto write(std::string message) -> Res<void>;
|
|
|
|
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 <typename Functor> class RpcServer {
|
|
public:
|
|
RpcServer(Functor&& functor)
|
|
: functor(functor) { };
|
|
|
|
auto listen() -> Res<void>
|
|
{
|
|
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<BufferedWriter>(*client);
|
|
this->functor(std::move(req.val()), std::move(writer));
|
|
message.clear();
|
|
goto message_done;
|
|
}
|
|
}
|
|
message_done:
|
|
}
|
|
std::unreachable();
|
|
};
|
|
|
|
private:
|
|
Functor functor;
|
|
};
|
|
|
|
};
|