diff options
| author | Per Larsson <[email protected]> | 2022-02-21 15:00:02 +0100 |
|---|---|---|
| committer | Per Larsson <[email protected]> | 2022-02-21 15:00:02 +0100 |
| commit | 41782efc63d7f88525596d6724a1bb86d6fdcfa4 (patch) | |
| tree | 80567b8cc256c361abb8f81b53680f2fa6ec6fcc | |
| parent | Refactored websocket message. (diff) | |
| download | zen-41782efc63d7f88525596d6724a1bb86d6fdcfa4.tar.xz zen-41782efc63d7f88525596d6724a1bb86d6fdcfa4.zip | |
Added option to enable websockets.
| -rw-r--r-- | zenhttp/include/zenhttp/websocket.h | 8 | ||||
| -rw-r--r-- | zenhttp/websocketasio.cpp | 51 | ||||
| -rw-r--r-- | zenserver-test/zenserver-test.cpp | 2 | ||||
| -rw-r--r-- | zenserver/config.cpp | 14 | ||||
| -rw-r--r-- | zenserver/config.h | 24 | ||||
| -rw-r--r-- | zenserver/zenserver.cpp | 20 |
6 files changed, 75 insertions, 44 deletions
diff --git a/zenhttp/include/zenhttp/websocket.h b/zenhttp/include/zenhttp/websocket.h index 336d98b42..a514e6002 100644 --- a/zenhttp/include/zenhttp/websocket.h +++ b/zenhttp/include/zenhttp/websocket.h @@ -139,7 +139,7 @@ private: */ struct WebSocketServerOptions { - uint16_t Port = 8848; + uint16_t Port = 2337; uint32_t ThreadCount = 1; }; @@ -151,8 +151,8 @@ class WebSocketServer public: virtual ~WebSocketServer() = default; - virtual bool Run(const WebSocketServerOptions& Options) = 0; - virtual void Shutdown() = 0; + virtual bool Run() = 0; + virtual void Shutdown() = 0; virtual void RegisterService(WebSocketService& Service) = 0; virtual void RegisterNotificationHandler(std::string_view Key, WebSocketService& Service) = 0; @@ -161,7 +161,7 @@ public: virtual void SendNotification(WebSocketMessage&& Notification) = 0; virtual void SendResponse(WebSocketMessage&& Response) = 0; - static std::unique_ptr<WebSocketServer> Create(); + static std::unique_ptr<WebSocketServer> Create(const WebSocketServerOptions& Options); }; /** diff --git a/zenhttp/websocketasio.cpp b/zenhttp/websocketasio.cpp index 13d0177ee..c2ce7ca64 100644 --- a/zenhttp/websocketasio.cpp +++ b/zenhttp/websocketasio.cpp @@ -582,10 +582,10 @@ WsThreadPool::Stop() class WsServer final : public WebSocketServer { public: - WsServer() = default; + WsServer(const WebSocketServerOptions& Options) : m_Options(Options) {} virtual ~WsServer() { Shutdown(); } - virtual bool Run(const WebSocketServerOptions& Options) override; + virtual bool Run() override; virtual void Shutdown() override; virtual void RegisterService(WebSocketService& Service) override; @@ -614,6 +614,7 @@ private: using RequestHandlerMap = std::unordered_map<std::string_view, WebSocketService*>; using NotificationHandlerMap = std::unordered_map<std::string_view, std::vector<WebSocketService*>>; + WebSocketServerOptions m_Options; asio::io_service m_IoSvc; std::unique_ptr<asio::ip::tcp::acceptor> m_Acceptor; std::unique_ptr<WsThreadPool> m_ThreadPool; @@ -634,7 +635,7 @@ WsServer::RegisterService(WebSocketService& Service) } bool -WsServer::Run(const WebSocketServerOptions& Options) +WsServer::Run() { m_Acceptor = std::make_unique<asio::ip::tcp::acceptor>(m_IoSvc, asio::ip::tcp::v6()); @@ -645,7 +646,7 @@ WsServer::Run(const WebSocketServerOptions& Options) m_Acceptor->set_option(asio::socket_base::send_buffer_size(256 * 1024)); asio::error_code Ec; - m_Acceptor->bind(asio::ip::tcp::endpoint(asio::ip::address_v6::any(), Options.Port), Ec); + m_Acceptor->bind(asio::ip::tcp::endpoint(asio::ip::address_v6::any(), m_Options.Port), Ec); if (Ec) { @@ -657,12 +658,12 @@ WsServer::Run(const WebSocketServerOptions& Options) m_Acceptor->listen(); m_Running = true; - ZEN_LOG_INFO(LogWebSocket, "web socket server running on port '{}'", Options.Port); + ZEN_LOG_INFO(LogWebSocket, "web socket server running on port '{}'", m_Options.Port); AcceptConnection(); m_ThreadPool = std::make_unique<WsThreadPool>(m_IoSvc); - m_ThreadPool->Start(Options.ThreadCount); + m_ThreadPool->Start(m_Options.ThreadCount); return true; } @@ -720,29 +721,29 @@ WsServer::AcceptConnection() asio::ip::tcp::socket& SocketRef = *Socket.get(); m_Acceptor->async_accept(SocketRef, [this, ConnectedSocket = std::move(Socket)](const asio::error_code& Ec) mutable { - if (Ec) - { - ZEN_LOG_WARN(LogWebSocket, "accept connection FAILED, reason '{}'", Ec.message()); - } - else + if (m_Running) { - auto Connection = std::make_shared<WsConnection>(WebSocketId::New(), std::move(ConnectedSocket)); - - ZEN_LOG_DEBUG(LogWebSocket, "accept connection '#{} {}' OK", Connection->Id().Value(), Connection->RemoteAddr()); - + if (Ec) { - std::unique_lock _(m_ConnMutex); - m_Connections[Connection->Id()] = Connection; + ZEN_LOG_WARN(LogWebSocket, "accept connection FAILED, reason '{}'", Ec.message()); } + else + { + auto Connection = std::make_shared<WsConnection>(WebSocketId::New(), std::move(ConnectedSocket)); - Connection->SetParser(std::make_unique<HttpMessageParser>(HttpMessageParserType::kRequest)); - Connection->SetState(WebSocketState::kHandshaking); + ZEN_LOG_DEBUG(LogWebSocket, "accept connection '#{} {}' OK", Connection->Id().Value(), Connection->RemoteAddr()); - ReadMessage(Connection); - } + { + std::unique_lock _(m_ConnMutex); + m_Connections[Connection->Id()] = Connection; + } + + Connection->SetParser(std::make_unique<HttpMessageParser>(HttpMessageParserType::kRequest)); + Connection->SetState(WebSocketState::kHandshaking); + + ReadMessage(Connection); + } - if (m_Running) - { AcceptConnection(); } }); @@ -1522,9 +1523,9 @@ WebSocketService::Configure(WebSocketServer& Server) } std::unique_ptr<WebSocketServer> -WebSocketServer::Create() +WebSocketServer::Create(const WebSocketServerOptions& Options) { - return std::make_unique<websocket::WsServer>(); + return std::make_unique<websocket::WsServer>(Options); } std::shared_ptr<WebSocketClient> diff --git a/zenserver-test/zenserver-test.cpp b/zenserver-test/zenserver-test.cpp index 78829a2d1..aac43f43a 100644 --- a/zenserver-test/zenserver-test.cpp +++ b/zenserver-test/zenserver-test.cpp @@ -2089,7 +2089,7 @@ TEST_CASE("websocket.basic") ZenServerInstance Inst(TestEnv); Inst.SetTestDir(TestDir); - Inst.SpawnServer(PortNumber); + Inst.SpawnServer(PortNumber, "--websocket-port=8848"sv); Inst.WaitUntilReady(); asio::io_context IoCtx; 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/zenserver.cpp b/zenserver/zenserver.cpp index 08abfdecd..78a62e202 100644 --- a/zenserver/zenserver.cpp +++ b/zenserver/zenserver.cpp @@ -205,7 +205,14 @@ public: m_Http = zen::CreateHttpServer(ServerOptions.HttpServerClass); int EffectiveBasePort = m_Http->Initialize(ServerOptions.BasePort); - m_WebSocket = zen::WebSocketServer::Create(); + 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 { @@ -305,9 +312,13 @@ public: m_Http->RegisterService(m_TestService); // NOTE: this is intentionally not limited to test mode as it's useful for diagnostics m_Http->RegisterService(m_TestingService); - m_WebSocket->RegisterService(m_TestingService); m_Http->RegisterService(m_AdminService); + if (m_WebSocket) + { + m_WebSocket->RegisterService(m_TestingService); + } + if (m_HttpProjectService) { m_Http->RegisterService(*m_HttpProjectService); @@ -400,7 +411,10 @@ public: OnReady(); - m_WebSocket->Run({.Port = 8848}); + if (m_WebSocket) + { + m_WebSocket->Run(); + } m_Http->Run(IsInteractiveMode); |