#pragma once #include #include #include #include #include #include #include #include #include #include "golpe.h" #include "Subscription.h" #include "ThreadPool.h" #include "events.h" #include "filters.h" #include "yesstr.h" struct MsgWebsocket : NonCopyable { struct Send { uint64_t connId; std::string payload; }; struct SendBinary { uint64_t connId; std::string payload; }; struct SendEventToBatch { RecipientList list; std::string evJson; }; using Var = std::variant; Var msg; MsgWebsocket(Var &&msg_) : msg(std::move(msg_)) {} }; struct MsgIngester : NonCopyable { struct ClientMessage { uint64_t connId; std::string ipAddr; std::string payload; }; struct CloseConn { uint64_t connId; }; using Var = std::variant; Var msg; MsgIngester(Var &&msg_) : msg(std::move(msg_)) {} }; struct MsgWriter : NonCopyable { struct AddEvent { uint64_t connId; std::string ipAddr; uint64_t receivedAt; std::string flatStr; std::string jsonStr; }; using Var = std::variant; Var msg; MsgWriter(Var &&msg_) : msg(std::move(msg_)) {} }; struct MsgReqWorker : NonCopyable { struct NewSub { Subscription sub; }; struct RemoveSub { uint64_t connId; SubId subId; }; struct CloseConn { uint64_t connId; }; using Var = std::variant; Var msg; MsgReqWorker(Var &&msg_) : msg(std::move(msg_)) {} }; struct MsgReqMonitor : NonCopyable { struct NewSub { Subscription sub; }; struct RemoveSub { uint64_t connId; SubId subId; }; struct CloseConn { uint64_t connId; }; struct DBChange { }; using Var = std::variant; Var msg; MsgReqMonitor(Var &&msg_) : msg(std::move(msg_)) {} }; struct MsgYesstr : NonCopyable { struct SyncRequest { uint64_t connId; std::string yesstrMessage; }; struct CloseConn { uint64_t connId; }; using Var = std::variant; Var msg; MsgYesstr(Var &&msg_) : msg(std::move(msg_)) {} }; struct MsgXor : NonCopyable { struct NewView { Subscription sub; uint64_t idSize; std::string query; }; struct QueryView { uint64_t connId; SubId subId; uint64_t queryId; std::string query; }; struct RemoveView { uint64_t connId; SubId subId; }; struct CloseConn { uint64_t connId; }; using Var = std::variant; Var msg; MsgXor(Var &&msg_) : msg(std::move(msg_)) {} }; struct RelayServer { std::unique_ptr hubTrigger; // Thread Pools ThreadPool tpWebsocket; ThreadPool tpIngester; ThreadPool tpWriter; ThreadPool tpReqWorker; ThreadPool tpReqMonitor; ThreadPool tpYesstr; ThreadPool tpXor; std::thread cronThread; void run(); void runWebsocket(ThreadPool::Thread &thr); void runIngester(ThreadPool::Thread &thr); void ingesterProcessEvent(lmdb::txn &txn, uint64_t connId, std::string ipAddr, secp256k1_context *secpCtx, const tao::json::value &origJson, std::vector &output); void ingesterProcessReq(lmdb::txn &txn, uint64_t connId, const tao::json::value &origJson); void ingesterProcessClose(lmdb::txn &txn, uint64_t connId, const tao::json::value &origJson); void ingesterProcessXor(lmdb::txn &txn, uint64_t connId, const tao::json::value &origJson); void runWriter(ThreadPool::Thread &thr); void runReqWorker(ThreadPool::Thread &thr); void runReqMonitor(ThreadPool::Thread &thr); void runYesstr(ThreadPool::Thread &thr); void runXor(ThreadPool::Thread &thr); void runCron(); // Utils (can be called by any thread) void sendToConn(uint64_t connId, std::string &&payload) { tpWebsocket.dispatch(0, MsgWebsocket{MsgWebsocket::Send{connId, std::move(payload)}}); hubTrigger->send(); } void sendToConnBinary(uint64_t connId, std::string &&payload) { tpWebsocket.dispatch(0, MsgWebsocket{MsgWebsocket::SendBinary{connId, std::move(payload)}}); hubTrigger->send(); } void sendEvent(uint64_t connId, const SubId &subId, std::string_view evJson) { auto subIdSv = subId.sv(); std::string reply; reply.reserve(13 + subIdSv.size() + evJson.size()); reply += "[\"EVENT\",\""; reply += subIdSv; reply += "\","; reply += evJson; reply += "]"; sendToConn(connId, std::move(reply)); } void sendEventToBatch(RecipientList &&list, std::string &&evJson) { tpWebsocket.dispatch(0, MsgWebsocket{MsgWebsocket::SendEventToBatch{std::move(list), std::move(evJson)}}); hubTrigger->send(); } void sendNoticeError(uint64_t connId, std::string &&payload) { LI << "sending error to [" << connId << "]: " << payload; auto reply = tao::json::value::array({ "NOTICE", std::string("ERROR: ") + payload }); tpWebsocket.dispatch(0, MsgWebsocket{MsgWebsocket::Send{connId, std::move(tao::json::to_string(reply))}}); hubTrigger->send(); } void sendOKResponse(uint64_t connId, std::string_view eventIdHex, bool written, std::string_view message) { auto reply = tao::json::value::array({ "OK", eventIdHex, written, message }); tpWebsocket.dispatch(0, MsgWebsocket{MsgWebsocket::Send{connId, std::move(tao::json::to_string(reply))}}); hubTrigger->send(); } };