#include "ydi_server.h" #include "ydi_networking.h" #include #include #include #include #include #include #include #include #include #include namespace ydi::server { struct Service { std::optional context{ std::nullopt }; std::optional socket{ std::nullopt }; std::unordered_set revealedClues{}; std::recursive_mutex mtx{}; std::optional client{ std::nullopt }; double lastHeart{ 0.0 }; double lastBeat{ 0.0 }; std::atomic stop_threads{ false }; }; std::optional service{ std::nullopt }; std::optional receiveThread{ std::nullopt }; std::optional pingThread{ std::nullopt }; void handle_reveal_clue(zmq::multipart_t const &message) { } void handle_authorised_message(std::string_view const &sender, std::string_view const &type, zmq::multipart_t &message) { if (type == "BEAT") { service->lastBeat = Time::get_singleton()->get_unix_time_from_system(); } else if(type == "REVEAL") { handle_reveal_clue(message); } else { multipart(sender, "NOK", "UNKOWN_COMMAND", message).send(*service->socket); } } void handle_message(zmq::multipart_t &message) { std::string_view const sender{ message.at(0).to_string_view() }; std::string_view const type{ message.at(1).to_string_view() }; std::scoped_lock lock{ service->mtx }; if (service->client) { if (sender != service->client) { multipart(sender,"NOK", "UNAUTHORIZED_REQUEST").send(*service->socket); } handle_authorised_message(sender, type, message); } else if (type == "CONNECT") { service->client.emplace(sender); multipart(sender, "OK", message).send(*service->socket); } else { multipart(sender,"NOK", "UNAUTHORIZED_REQUEST", message).send(*service->socket); } } void receive_thread_entry() { using namespace std::chrono_literals; zmq::multipart_t incoming{}; while (service->stop_threads) { std::this_thread::sleep_for(20ms); std::scoped_lock lock{ service->mtx }; if (incoming.recv(*service->socket)) { handle_message(incoming); } } } void ping_thread_entry() { using namespace std::chrono_literals; { std::scoped_lock lock{ service->mtx }; if (!service->client) { return; } } static zmq::multipart_t ping{ multipart(*service->client, "HEART") }; while (!service->stop_threads) { std::this_thread::sleep_for(1s); std::scoped_lock lock{ service->mtx }; ping.send(*service->socket); service->lastHeart = Time::get_singleton()->get_unix_time_from_system(); } } void open() { service.emplace(); try { service->context.emplace(1); } catch (...) { service.reset(); return; } try { service->socket.emplace(*service->context, zmq::socket_type::router); } catch (...) { service->context->close(); service->context.reset(); service.reset(); return; } try { service->socket->connect("tcp://*:6667"); } catch (...) { service->socket->close(); service->socket.reset(); service->context->close(); service->context.reset(); service.reset(); } receiveThread.emplace(receive_thread_entry); } void close() { if (service) { std::scoped_lock lock{ service->mtx }; if (service->socket) { service->socket->close(); service->socket.reset(); } if (service->context) { service->context->close(); service->context.reset(); } service.reset(); } } }