From a8a72c30540a0d01f19fa60c63956b320cfb580f Mon Sep 17 00:00:00 2001 From: Kieran Date: Wed, 29 Nov 2023 22:54:42 +0000 Subject: [PATCH] refactor: re-implement uWS::App --- include/server.hpp | 152 +++++++++++++++++++++++++++++++++++++++++++++ src/main.cpp | 86 ++----------------------- 2 files changed, 158 insertions(+), 80 deletions(-) create mode 100644 include/server.hpp diff --git a/include/server.hpp b/include/server.hpp new file mode 100644 index 0000000..d10a32e --- /dev/null +++ b/include/server.hpp @@ -0,0 +1,152 @@ +#pragma once + +#include "HttpContext.h" +#include "HttpResponse.h" +#include "WebSocketContext.h" +#include "WebSocket.h" + +#include "state.h" +#include "json.hpp" +#include "request.hpp" +#include "proxy.hpp" +#include "socket.hpp" + +namespace uWS +{ + template + class NostrServer + { + private: + uWS::HttpContext *httpContext; + + static auto handleMessage(const std::string_view &message, const StateObj *state) -> void + { + try + { + auto j = nlohmann::json::parse(message); + if (!j.is_array()) + { + return; + } + + auto q = j[0].get(); + if (q == "REQ") + { + auto filter = NostrRequest::from_json(j); + state->proxy->push(std::move(filter)); + } + else if (q == "EVENT") + { + auto id = j[1]["id"].get(); + // do something + state->socket->ok(id, false, "not implemented"); + } + else if (q == "CLOSE") + { + // nothing + } + else + { + state->socket->notice("Command not supported"); + } + } + catch (const std::exception &e) + { + state->socket->notice("Unknown error: " + std::string(e.what())); + } + } + + public: + NostrServer() + { + us_socket_context_options_t options = {}; + httpContext = uWS::HttpContext::create(uWS::Loop::get(), options); + } + + auto ws(std::string path) + { + auto openHandler = [](auto *ws) + { + StateObj *state = ws->getUserData(); + std::cout << "New connection: " << ws->getRemoteAddressAsText() << std::endl; + state->socket = new relay_middleware::nostr::NostrSocket(ws); + state->proxy = new relay_middleware::proxy::RelayProxy("http://localhost:5167"); + }; + auto closeHandler = [](auto *ws, auto code, auto msg) + { + StateObj *state = ws->getUserData(); + delete state->proxy; + delete state->socket; + delete state; + }; + auto messageHandler = [](auto *ws, std::string_view message, uWS::OpCode opCode) + { + std::cout << "In: " << message << std::endl; + if (opCode == uWS::OpCode::TEXT) + { + NostrServer::handleMessage(message, ws->getUserData()); + } + }; + auto *webSocketContext = uWS::WebSocketContext::create(uWS::Loop::get(), (us_socket_context_t *)httpContext, nullptr); + auto wsExt = (WebSocketContextData *)us_socket_context_ext(SSL, (us_socket_context_t *)webSocketContext); + /* Copy all handlers */ + wsExt->openHandler = std::move(openHandler); + wsExt->messageHandler = std::move(messageHandler); + wsExt->drainHandler = std::move(nullptr); + wsExt->subscriptionHandler = std::move(nullptr); + wsExt->closeHandler = std::move(closeHandler); + wsExt->pingHandler = std::move(nullptr); + wsExt->pongHandler = std::move(nullptr); + + /* Copy settings */ + wsExt->maxPayloadLength = 128 * 1024; + wsExt->maxBackpressure = 64 * 1024; + wsExt->closeOnBackpressureLimit = true; + wsExt->resetIdleTimeoutOnSend = true; + wsExt->sendPingsAutomatically = true; + wsExt->maxLifetime = 60; + wsExt->compression = uWS::CompressOptions::DISABLED; + + /* Calculate idleTimeoutCompnents */ + wsExt->calculateIdleTimeoutCompnents(60); + + auto reqHandler = [webSocketContext](uWS::HttpResponse *res, uWS::HttpRequest *req) mutable + { + auto accept = req->getHeader("accept"); + if (accept == "application/nostr+json") + { + res->write("{}"); + res->end(); + return; + } + else + { + /* If we have this header set, it's a websocket */ + auto secWebSocketKey = req->getHeader("sec-websocket-key"); + if (secWebSocketKey.length() == 24) + { + /* Default handler upgrades to WebSocket */ + std::string_view secWebSocketProtocol = req->getHeader("sec-websocket-protocol"); + std::string_view secWebSocketExtensions = req->getHeader("sec-websocket-extensions"); + res->template upgrade({}, secWebSocketKey, secWebSocketProtocol, secWebSocketExtensions, (struct us_socket_context_t *)webSocketContext); + } + else + { + /* Tell the router that we did not handle this request */ + req->setYield(true); + } + } + }; + + httpContext->onHttp("GET", path, std::move(reqHandler), true); + } + + auto run(int port) + { + httpContext->listen(nullptr, port, 0); + uWS::run(); + } + }; + + typedef NostrServer App; +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 3d4237e..5d36807 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,86 +1,12 @@ -#include - -#include "App.h" -#include "json.hpp" -#include "request.hpp" -#include "proxy.hpp" -#include "socket.hpp" -#include "state.h" - -void handleMessage(const std::string_view &message, const StateObj *state) -{ - try - { - auto j = nlohmann::json::parse(message); - if (!j.is_array()) - { - return; - } - - auto q = j[0].get(); - if (q == "REQ") - { - auto filter = NostrRequest::from_json(j); - state->proxy->push(std::move(filter)); - } - else if (q == "EVENT") - { - auto id = j[1]["id"].get(); - // do something - state->socket->ok(id, false, "not implemented"); - } - else if (q == "CLOSE") - { - // nothing - } - else - { - state->socket->notice("Command not supported"); - } - } - catch (const std::exception &e) - { - state->socket->notice("Unknown error: " + std::string(e.what())); - } -} +#include "server.hpp" int main() { - auto openHandler = [](auto *ws) - { - StateObj *state = ws->getUserData(); - std::cout << "New connection" << std::endl; - state->socket = new relay_middleware::nostr::NostrSocket(ws); - state->proxy = new relay_middleware::proxy::RelayProxy("http://localhost:5167"); - }; - auto closeHandler = [](auto *ws, auto code, auto msg) - { - StateObj *state = ws->getUserData(); - delete state->proxy; - delete state->socket; - }; - auto messageHandler = [](auto *ws, std::string_view message, uWS::OpCode opCode) - { - std::cout << "In: " << message << std::endl; - if (opCode == uWS::OpCode::TEXT) - { - handleMessage(message, ws->getUserData()); - } - }; - auto listenHandler = [](auto *listen_socket) - { - if (listen_socket) - { - std::cout << "Listening on port " << 3334 << std::endl; - } - }; + constexpr auto port = 3334; - uWS::App::WebSocketBehavior params = {}; - params.open = openHandler; - params.close = closeHandler; - params.message = messageHandler; + auto server = new uWS::App(); + server->ws("/"); + server->run(port); - uWS::App().ws("/", std::move(params)).listen(3334, listenHandler).run(); - - std::cout << "Failed to listen on port 3334" << std::endl; + std::cout << "Failed to listen on port {port}" << std::endl; } \ No newline at end of file