refactor: re-implement uWS::App

This commit is contained in:
Kieran 2023-11-29 22:54:42 +00:00
parent 448eecb114
commit a8a72c3054
Signed by: Kieran
GPG Key ID: DE71CEB3925BE941
2 changed files with 158 additions and 80 deletions

152
include/server.hpp Normal file
View File

@ -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 <bool SSL>
class NostrServer
{
private:
uWS::HttpContext<SSL> *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<std::string>();
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<std::string>();
// 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<SSL>::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<SSL, true, StateObj>::create(uWS::Loop::get(), (us_socket_context_t *)httpContext, nullptr);
auto wsExt = (WebSocketContextData<SSL, StateObj> *)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<SSL> *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<StateObj>({}, 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<false> App;
}

View File

@ -1,86 +1,12 @@
#include <sstream>
#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<std::string>();
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<std::string>();
// 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<StateObj> params = {};
params.open = openHandler;
params.close = closeHandler;
params.message = messageHandler;
auto server = new uWS::App();
server->ws("/");
server->run(port);
uWS::App().ws<StateObj>("/", 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;
}