aboutsummaryrefslogtreecommitdiff
path: root/zenserver
diff options
context:
space:
mode:
authorPer Larsson <[email protected]>2022-02-21 15:14:11 +0100
committerPer Larsson <[email protected]>2022-02-21 15:14:11 +0100
commitdb1c9605e3afbaf86f4231ba4eb7976d896f286b (patch)
tree54b451da4247c69575ff1a05ed006ecef3905c85 /zenserver
parentIf open(O_CREAT) is used then a file mode must be given (diff)
parentRemoved optional offset for GetView. (diff)
downloadzen-db1c9605e3afbaf86f4231ba4eb7976d896f286b.tar.xz
zen-db1c9605e3afbaf86f4231ba4eb7976d896f286b.zip
Initial support for websockets.
Diffstat (limited to 'zenserver')
-rw-r--r--zenserver/config.cpp14
-rw-r--r--zenserver/config.h24
-rw-r--r--zenserver/testing/httptest.cpp34
-rw-r--r--zenserver/testing/httptest.h6
-rw-r--r--zenserver/zenserver.cpp21
5 files changed, 87 insertions, 12 deletions
diff --git a/zenserver/config.cpp b/zenserver/config.cpp
index cb6d5ea6d..bcacc16c0 100644
--- a/zenserver/config.cpp
+++ b/zenserver/config.cpp
@@ -193,6 +193,20 @@ ParseCliOptions(int argc, char* argv[], ZenServerOptions& ServerOptions)
cxxopts::value<int>(ServerOptions.BasePort)->default_value("1337"),
"<port number>");
+ options.add_option("network",
+ "",
+ "websocket-port",
+ "Websocket server port",
+ cxxopts::value<int>(ServerOptions.WebSocketPort)->default_value("0"),
+ "<port number>");
+
+ options.add_option("network",
+ "",
+ "websocket-threads",
+ "Number of websocket I/O thread(s) (0 == hardware concurrency)",
+ cxxopts::value<int>(ServerOptions.WebSocketThreads)->default_value("0"),
+ "");
+
#if ZEN_ENABLE_MESH
options.add_option("network",
"m",
diff --git a/zenserver/config.h b/zenserver/config.h
index 69e65498c..fd569bdb1 100644
--- a/zenserver/config.h
+++ b/zenserver/config.h
@@ -87,17 +87,19 @@ struct ZenServerOptions
{
ZenUpstreamCacheConfig UpstreamCacheConfig;
ZenGcConfig GcConfig;
- std::filesystem::path DataDir; // Root directory for state (used for testing)
- std::filesystem::path ContentDir; // Root directory for serving frontend content (experimental)
- std::filesystem::path AbsLogFile; // Absolute path to main log file
- std::filesystem::path ConfigFile; // Path to Lua config file
- std::string ChildId; // Id assigned by parent process (used for lifetime management)
- std::string LogId; // Id for tagging log output
- std::string HttpServerClass; // Choice of HTTP server implementation
- std::string EncryptionKey; // 256 bit AES encryption key
- std::string EncryptionIV; // 128 bit AES initialization vector
- int BasePort = 1337; // Service listen port (used for both UDP and TCP)
- int OwnerPid = 0; // Parent process id (zero for standalone)
+ std::filesystem::path DataDir; // Root directory for state (used for testing)
+ std::filesystem::path ContentDir; // Root directory for serving frontend content (experimental)
+ std::filesystem::path AbsLogFile; // Absolute path to main log file
+ std::filesystem::path ConfigFile; // Path to Lua config file
+ std::string ChildId; // Id assigned by parent process (used for lifetime management)
+ std::string LogId; // Id for tagging log output
+ std::string HttpServerClass; // Choice of HTTP server implementation
+ std::string EncryptionKey; // 256 bit AES encryption key
+ std::string EncryptionIV; // 128 bit AES initialization vector
+ int BasePort = 1337; // Service listen port (used for both UDP and TCP)
+ int OwnerPid = 0; // Parent process id (zero for standalone)
+ int WebSocketPort = 0; // Web socket port (Zero = disabled)
+ int WebSocketThreads = 0;
bool InstallService = false; // Flag used to initiate service install (temporary)
bool UninstallService = false; // Flag used to initiate service uninstall (temporary)
bool IsDebug = false;
diff --git a/zenserver/testing/httptest.cpp b/zenserver/testing/httptest.cpp
index 230d5d6c5..10b69c469 100644
--- a/zenserver/testing/httptest.cpp
+++ b/zenserver/testing/httptest.cpp
@@ -8,6 +8,8 @@
namespace zen {
+using namespace std::literals;
+
HttpTestingService::HttpTestingService()
{
m_Router.RegisterRoute(
@@ -136,6 +138,38 @@ HttpTestingService::HandlePackageRequest(HttpServerRequest& HttpServiceRequest)
return (InsertResult.first->second = new PackageHandler(*this, RequestId)).Get();
}
+void
+HttpTestingService::RegisterHandlers(WebSocketServer& Server)
+{
+ Server.RegisterRequestHandler("SayHello"sv, *this);
+}
+
+bool
+HttpTestingService::HandleRequest(const WebSocketMessage& RequestMsg)
+{
+ CbObjectView Request = RequestMsg.Body().GetObject();
+
+ std::string_view Method = Request["Method"].AsString();
+
+ if (Method != "SayHello"sv)
+ {
+ return false;
+ }
+
+ CbObjectWriter Response;
+ Response.AddString("Result"sv, "Hello Friend!!");
+
+ WebSocketMessage ResponseMsg;
+ ResponseMsg.SetMessageType(WebSocketMessageType::kResponse);
+ ResponseMsg.SetCorrelationId(RequestMsg.CorrelationId());
+ ResponseMsg.SetSocketId(RequestMsg.SocketId());
+ ResponseMsg.SetBody(Response.Save());
+
+ SocketServer().SendResponse(std::move(ResponseMsg));
+
+ return true;
+}
+
//////////////////////////////////////////////////////////////////////////
HttpTestingService::PackageHandler::PackageHandler(HttpTestingService& Svc, uint32_t RequestId) : m_Svc(Svc), m_RequestId(RequestId)
diff --git a/zenserver/testing/httptest.h b/zenserver/testing/httptest.h
index f7ea0c31c..57d2d63f3 100644
--- a/zenserver/testing/httptest.h
+++ b/zenserver/testing/httptest.h
@@ -5,6 +5,7 @@
#include <zencore/logging.h>
#include <zencore/stats.h>
#include <zenhttp/httpserver.h>
+#include <zenhttp/websocket.h>
#include <atomic>
@@ -13,7 +14,7 @@ namespace zen {
/**
* Test service to facilitate testing the HTTP framework and client interactions
*/
-class HttpTestingService : public HttpService
+class HttpTestingService : public HttpService, public WebSocketService
{
public:
HttpTestingService();
@@ -40,6 +41,9 @@ public:
};
private:
+ virtual void RegisterHandlers(WebSocketServer& Server) override;
+ virtual bool HandleRequest(const WebSocketMessage& Request) override;
+
HttpRequestRouter m_Router;
std::atomic<uint32_t> m_Counter{0};
metrics::OperationTiming m_TimingStats;
diff --git a/zenserver/zenserver.cpp b/zenserver/zenserver.cpp
index ea0f52db2..78a62e202 100644
--- a/zenserver/zenserver.cpp
+++ b/zenserver/zenserver.cpp
@@ -15,6 +15,7 @@
#include <zencore/timer.h>
#include <zencore/trace.h>
#include <zenhttp/httpserver.h>
+#include <zenhttp/websocket.h>
#include <zenstore/basicfile.h>
#include <zenstore/cas.h>
#include <zenstore/cidstore.h>
@@ -204,6 +205,15 @@ public:
m_Http = zen::CreateHttpServer(ServerOptions.HttpServerClass);
int EffectiveBasePort = m_Http->Initialize(ServerOptions.BasePort);
+ if (ServerOptions.WebSocketPort != 0)
+ {
+ const uint32 ThreadCount =
+ ServerOptions.WebSocketThreads > 0 ? uint32_t(ServerOptions.WebSocketThreads) : std::thread::hardware_concurrency();
+
+ m_WebSocket = zen::WebSocketServer::Create(
+ {.Port = gsl::narrow<uint16_t>(ServerOptions.WebSocketPort), .ThreadCount = Max(ThreadCount, uint32_t(16))});
+ }
+
// Setup authentication manager
{
std::string EncryptionKey = ServerOptions.EncryptionKey;
@@ -304,6 +314,11 @@ public:
m_Http->RegisterService(m_TestingService);
m_Http->RegisterService(m_AdminService);
+ if (m_WebSocket)
+ {
+ m_WebSocket->RegisterService(m_TestingService);
+ }
+
if (m_HttpProjectService)
{
m_Http->RegisterService(*m_HttpProjectService);
@@ -396,6 +411,11 @@ public:
OnReady();
+ if (m_WebSocket)
+ {
+ m_WebSocket->Run();
+ }
+
m_Http->Run(IsInteractiveMode);
SetNewState(kShuttingDown);
@@ -559,6 +579,7 @@ private:
}
zen::Ref<zen::HttpServer> m_Http;
+ std::unique_ptr<zen::WebSocketServer> m_WebSocket;
std::unique_ptr<zen::AuthMgr> m_AuthMgr;
std::unique_ptr<zen::HttpAuthService> m_AuthService;
zen::HttpStatusService m_StatusService;