diff --git a/src/network/websocket/WebSocketServer.cpp b/src/network/websocket/WebSocketServer.cpp index fb12444d0..974db657a 100644 --- a/src/network/websocket/WebSocketServer.cpp +++ b/src/network/websocket/WebSocketServer.cpp @@ -83,27 +83,6 @@ bool SingleClientWSServer::addProtocol(std::unique_ptr protoc std::string path = protocol->getProtocolPath(); if (protocolMap.find(path) == protocolMap.end()) { protocolMap.emplace(path, std::move(protocol)); - auto& protocolData = protocolMap.at(path); - const auto& heartbeatInfo = protocolData.protocol->heartbeatInfo; - if (heartbeatInfo.has_value()) { - auto eventID = - pingScheduler.scheduleEvent(heartbeatInfo->first / 2, [this, path]() { - auto& pd = this->protocolMap.at(path); - std::lock_guard lock(pd.mutex); - if (pd.client.has_value()) { - log(LOG_DEBUG, "Ping!\n"); - server.ping(pd.client.value(), path); - } - }); - std::lock_guard l(protocolData.mutex); - // util::Watchdog is non-copyable and non-movable, so we must create in-place - // Since we want to create a member field of the pair in-place, it gets complicated - // so we have to use piecewise_construct to allow us to separately initialize all - // pair fields in-place - protocolData.heartbeatInfo.emplace(std::piecewise_construct, - std::tuple{eventID}, - util::pairToTuple(heartbeatInfo.value())); - } return true; } else { return false; @@ -159,8 +138,31 @@ void SingleClientWSServer::onOpen(connection_hdl hdl) { path.c_str(), client.c_str()); auto& protocolData = protocolMap.at(path); - protocolData.client = hdl; - protocolData.protocol->clientConnected(); + { + std::lock_guard lock(protocolData.mutex); + protocolData.client = hdl; + const auto& heartbeatInfo = protocolData.protocol->heartbeatInfo; + if (heartbeatInfo.has_value()) { + auto eventID = + pingScheduler.scheduleEvent(heartbeatInfo->first / 2, [this, path]() { + auto& pd = this->protocolMap.at(path); + std::lock_guard lock(pd.mutex); + if (pd.client.has_value()) { + log(LOG_DEBUG, "Ping!\n"); + server.ping(pd.client.value(), path); + } + }); + // util::Watchdog is non-copyable and non-movable, so we must create in-place + // Since we want to create a member field of the pair in-place, it gets complicated + // so we have to use piecewise_construct to allow us to separately initialize all + // pair fields in-place + protocolData.heartbeatInfo.emplace(std::piecewise_construct, + std::tuple{eventID}, + util::pairToTuple(heartbeatInfo.value())); + } + + protocolData.protocol->clientConnected(); + } } void SingleClientWSServer::onClose(connection_hdl hdl) { diff --git a/src/network/websocket/WebSocketServer.h b/src/network/websocket/WebSocketServer.h index f44e025c7..e916d8134 100644 --- a/src/network/websocket/WebSocketServer.h +++ b/src/network/websocket/WebSocketServer.h @@ -99,6 +99,7 @@ class SingleClientWSServer { ProtocolData(std::unique_ptr protocol); const std::unique_ptr protocol; std::optional client; + // holds the periodically scheduled ping event and the watchdog std::optional::eventid_t, util::Watchdog<>>> heartbeatInfo; std::mutex mutex; @@ -108,14 +109,20 @@ class SingleClientWSServer { uint16_t port; websocketpp::server server; bool isRunning; + // maps path prefix to ProtocolData for each protocol std::map protocolMap; std::thread serverThread; util::PeriodicScheduler<> pingScheduler; + // called when connection is received and being validated. + // return true to accept, false to reject bool validate(connection_hdl hdl); + // called when connection is opened void onOpen(connection_hdl hdl); + // called when connection is closed void onClose(connection_hdl hdl); void onMessage(connection_hdl hdl, message_t message); + // called when pong message received from WS client void onPong(connection_hdl hdl, const std::string& payload); void serverTask(); };