From b6a79ec5ef673be62abc87dbde9dab54396e00fb Mon Sep 17 00:00:00 2001 From: Victor Lindquist <VLLindqvist@users.noreply.github.com> Date: Wed, 15 Jun 2022 18:41:57 -0600 Subject: [PATCH] Refactored NetworkEngine and PointDataMessageHandler into Data-Oriented Design to simplify development --- modules/softwareintegration/CMakeLists.txt | 8 +- ...amessagehandler.cpp => messagehandler.cpp} | 578 ++++++++++-------- modules/softwareintegration/messagehandler.h | 50 ++ .../softwareintegration/network/network.cpp | 132 ++++ .../network/{networkengine.h => network.h} | 61 +- .../network/networkengine.cpp | 245 -------- .../network/softwareconnection.cpp | 105 ++-- .../network/softwareconnection.h | 72 +-- .../pointdatamessagehandler.h | 106 ---- .../softwareintegrationmodule.cpp | 25 +- .../softwareintegrationmodule.h | 6 +- modules/softwareintegration/utils.cpp | 15 + modules/softwareintegration/utils.h | 8 - 13 files changed, 672 insertions(+), 739 deletions(-) rename modules/softwareintegration/{pointdatamessagehandler.cpp => messagehandler.cpp} (84%) create mode 100644 modules/softwareintegration/messagehandler.h create mode 100644 modules/softwareintegration/network/network.cpp rename modules/softwareintegration/network/{networkengine.h => network.h} (69%) delete mode 100644 modules/softwareintegration/network/networkengine.cpp delete mode 100644 modules/softwareintegration/pointdatamessagehandler.h diff --git a/modules/softwareintegration/CMakeLists.txt b/modules/softwareintegration/CMakeLists.txt index d881cdff0..f6febd9ad 100644 --- a/modules/softwareintegration/CMakeLists.txt +++ b/modules/softwareintegration/CMakeLists.txt @@ -26,9 +26,9 @@ include(${OPENSPACE_CMAKE_EXT_DIR}/module_definition.cmake) set(HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/softwareintegrationmodule.h - ${CMAKE_CURRENT_SOURCE_DIR}/pointdatamessagehandler.h + ${CMAKE_CURRENT_SOURCE_DIR}/messagehandler.h + ${CMAKE_CURRENT_SOURCE_DIR}/network/network.h ${CMAKE_CURRENT_SOURCE_DIR}/network/softwareconnection.h - ${CMAKE_CURRENT_SOURCE_DIR}/network/networkengine.h ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderablepointscloud.h ${CMAKE_CURRENT_SOURCE_DIR}/utils.h ${CMAKE_CURRENT_SOURCE_DIR}/syncablefloatdatastorage.h @@ -41,9 +41,9 @@ source_group("Header Files" FILES ${HEADER_FILES}) set(SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/softwareintegrationmodule.cpp ${CMAKE_CURRENT_SOURCE_DIR}/softwareintegrationmodule_lua.inl - ${CMAKE_CURRENT_SOURCE_DIR}/pointdatamessagehandler.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/messagehandler.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/network/network.cpp ${CMAKE_CURRENT_SOURCE_DIR}/network/softwareconnection.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/network/networkengine.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderablepointscloud.cpp ${CMAKE_CURRENT_SOURCE_DIR}/utils.cpp ${CMAKE_CURRENT_SOURCE_DIR}/syncablefloatdatastorage.cpp diff --git a/modules/softwareintegration/pointdatamessagehandler.cpp b/modules/softwareintegration/messagehandler.cpp similarity index 84% rename from modules/softwareintegration/pointdatamessagehandler.cpp rename to modules/softwareintegration/messagehandler.cpp index ec0ae675c..25f6cf64c 100644 --- a/modules/softwareintegration/pointdatamessagehandler.cpp +++ b/modules/softwareintegration/messagehandler.cpp @@ -22,7 +22,7 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include <modules/softwareintegration/pointdatamessagehandler.h> +#include <modules/softwareintegration/messagehandler.h> #include <modules/softwareintegration/softwareintegrationmodule.h> #include <modules/softwareintegration/utils.h> @@ -41,14 +41,219 @@ #include <iomanip> namespace { - constexpr const char* _loggerCat = "PDatMessHand"; + +constexpr const char* _loggerCat = "PDatMessHand"; + } // namespace -namespace openspace { +namespace openspace::softwareintegration::network { + +// Anonymous namespace +namespace { + +CallbackMap callbacks{}; +std::mutex callbacksMutex{}; +size_t callbacksRetries{0}; + +const Renderable* getRenderable(const std::string& identifier) { + return renderable(identifier); +} + +void checkRenderable( + const std::vector<char>& message, size_t& messageOffset, + std::shared_ptr<SoftwareConnection> connection, std::string& identifier +) { + std::string guiName; + + try { + // The following order of creating variables is the exact order they are received + // in the message. If the order is not the same, the global variable + // 'message offset' will be wrong + identifier = simp::readString(message, messageOffset); + guiName = simp::readString(message, messageOffset); + } + catch (const simp::SimpError& err) { + LERROR(fmt::format("Error when reading identifier and guiName from message: {}", err.message)); + return; + } + + connection->addSceneGraphNode(identifier); + + auto r = renderable(identifier); + bool hasCallbacks = false; + { + std::lock_guard guard(callbacksMutex); + hasCallbacks = callbacks.count(identifier) > 0; + } + if (!r && !hasCallbacks) { + LDEBUG(fmt::format("No renderable with identifier '{}' was found. Creating it.", identifier)); + + // Create a renderable, since it didn't exist + using namespace std::string_literals; + ghoul::Dictionary renderablePointsCloud; + renderablePointsCloud.setValue("Type", "RenderablePointsCloud"s); + renderablePointsCloud.setValue("Identifier", identifier); + renderablePointsCloud.setValue("Name", guiName); + + ghoul::Dictionary gui; + gui.setValue("Name", guiName); + gui.setValue("Path", "/Software Integration"s); + + ghoul::Dictionary node; + node.setValue("Identifier", identifier); + node.setValue("Renderable", renderablePointsCloud); + node.setValue("GUI", gui); + + global::scriptEngine->queueScript( + "openspace.addSceneGraphNode(" + ghoul::formatLua(node) + ")" + "openspace.setPropertyValueSingle('Modules.CefWebGui.Reload', nil)", // Reload WebGUI so that SoftwareIntegration GUI appears + scripting::ScriptEngine::RemoteScripting::Yes + ); + } +} -using namespace softwareintegration; +void addCallback( + const std::string& identifier, + const Callback& newCallback +) { + std::lock_guard guard(callbacksMutex); + auto it = callbacks.find(identifier); + if (it == callbacks.end()) { + CallbackList newCallbackList{ newCallback }; + callbacks.emplace(identifier, newCallbackList); + } + else { + it->second.push_back(newCallback); + } +} -void PointDataMessageHandler::handlePointDataMessage(const std::vector<char>& message, std::shared_ptr<SoftwareConnection> connection) { +void onFixedColorChange( + properties::Property* property, + const std::string& identifier, + std::shared_ptr<SoftwareConnection> connection +) { + if (!connection->isConnected()) { + connection->removePropertySubscription(property->identifier(), identifier); + return; + } + + // auto propertySubscription = connection->getPropertySubscription(identifier, property->identifier()); + // if (!propertySubscription) return; + // if (!propertySubscription->shouldSendMessage) { + // propertySubscription->shouldSendMessage = true; + // return; + // } + + glm::vec4 color = std::any_cast<glm::vec4>(property->get()); + + const std::string message = simp::formatColorMessage(identifier, color); + connection->sendMessage(message); +} + +void onOpacityChange( + properties::Property* property, + const std::string& identifier, + std::shared_ptr<SoftwareConnection> connection +) { + if (!connection->isConnected()) { + connection->removePropertySubscription(property->identifier(), identifier); + return; + } + + // auto propertySubscription = connection->getPropertySubscription(identifier, property->identifier()); + // if (!propertySubscription) return; + // if (!propertySubscription->shouldSendMessage) { + // propertySubscription->shouldSendMessage = true; + // return; + // } + + float value = std::any_cast<float>(property->get()); + std::string hex_value = simp::floatToHex(value); + + const std::string message = simp::formatUpdateMessage(simp::MessageType::Opacity, identifier, hex_value); + connection->sendMessage(message); +} + +void onFixedPointSizeChange( + properties::Property* property, + const std::string& identifier, + std::shared_ptr<SoftwareConnection> connection +) { + if (!connection->isConnected()) { + connection->removePropertySubscription(property->identifier(), identifier); + return; + } + + // auto propertySubscription = connection->getPropertySubscription(identifier, property->identifier()); + // if (!propertySubscription) return; + // if (!propertySubscription->shouldSendMessage) { + // propertySubscription->shouldSendMessage = true; + // return; + // } + + float value = std::any_cast<float>(property->get()); + std::string hex_value = simp::floatToHex(value); + + const std::string message = simp::formatUpdateMessage(simp::MessageType::FixedSize, identifier, hex_value); + connection->sendMessage(message); +} + +void onVisibilityChange( + properties::Property* property, + const std::string& identifier, + std::shared_ptr<SoftwareConnection> connection +) { + if (!connection->isConnected()) { + connection->removePropertySubscription(property->identifier(), identifier); + return; + } + + // auto propertySubscription = connection->getPropertySubscription(identifier, property->identifier()); + // if (!propertySubscription) return; + // if (!propertySubscription->shouldSendMessage) { + // propertySubscription->shouldSendMessage = true; + // return; + // } + + bool isVisible = std::any_cast<bool>(property->get()); + std::string_view visibilityFlag = isVisible ? "T" : "F"; + + const std::string message = simp::formatUpdateMessage(simp::MessageType::Visibility, identifier, visibilityFlag); + connection->sendMessage(message); +} + +// TODO: Move to SIMP / use distanceconversion +void convertToMeterPerSecond(simp::LengthUnit currLengthUnit, std::vector<float>& data) { + // distanceconversion::convertDistance + float multiplier = 1.0; + switch (currLengthUnit) { + case simp::LengthUnit::km: + multiplier = 1000.0; + break; + case simp::LengthUnit::AU: + multiplier = static_cast<float>(distanceconstants::AstronomicalUnit); + break; + case simp::LengthUnit::lyr: + multiplier = static_cast<float>(distanceconstants::LightYear); + break; + case simp::LengthUnit::pc: + multiplier = static_cast<float>(distanceconstants::Parsec); + break; + case simp::LengthUnit::kpc: + multiplier = static_cast<float>(distanceconstants::Parsec * 1.0e3); + break; + case simp::LengthUnit::Mpc: + multiplier = static_cast<float>(distanceconstants::Parsec * 1.0e6); + break; + default: + break; + } + + std::transform(std::begin(data), std::end(data), std::begin(data), + [multiplier] (float f) {return f * multiplier;}); +} + +void handlePointDataMessage(const std::vector<char>& message, std::shared_ptr<SoftwareConnection> connection) { size_t messageOffset = 0; std::string identifier; @@ -86,8 +291,8 @@ void PointDataMessageHandler::handlePointDataMessage(const std::vector<char>& me addCallback(identifier, { reanchorCallback, { storage::Key::DataPoints }, "reanchorCallback" }); } -void PointDataMessageHandler::handleVelocityDataMessage(const std::vector<char>& message, std::shared_ptr<SoftwareConnection> connection) { - LWARNING(fmt::format("PointDataMessageHandler::handleVelocityDataMessage()")); +void handleVelocityDataMessage(const std::vector<char>& message, std::shared_ptr<SoftwareConnection> connection) { + LWARNING(fmt::format("handleVelocityDataMessage()")); size_t messageOffset = 0; std::string identifier; @@ -139,10 +344,11 @@ void PointDataMessageHandler::handleVelocityDataMessage(const std::vector<char>& auto module = global::moduleEngine->module<SoftwareIntegrationModule>(); module->storeData(identifier, storage::Key::VelocityData, std::move(velocities)); - auto velNaNModeCallback = [this, identifier, velNaNMode, velNaNColor, connection] { + auto velNaNModeCallback = [identifier, velNaNMode, velNaNColor, connection] { if (velNaNMode == simp::NaNRenderMode::Color) { // Get renderable auto r = getRenderable(identifier); + if (!r) return; // Get velNaNColor of renderable properties::Property* velNaNColorProperty = r->property("VelNaNColor"); @@ -182,7 +388,7 @@ void PointDataMessageHandler::handleVelocityDataMessage(const std::vector<char>& addCallback(identifier, { enableMotionCallback, { storage::Key::VelocityData }, "Enable motion mode, wait for VelocityData" }); } -void PointDataMessageHandler::handleFixedColorMessage(const std::vector<char>& message, std::shared_ptr<SoftwareConnection> connection) { +void handleFixedColorMessage(const std::vector<char>& message, std::shared_ptr<SoftwareConnection> connection) { size_t messageOffset = 0; std::string identifier; @@ -207,7 +413,7 @@ void PointDataMessageHandler::handleFixedColorMessage(const std::vector<char>& m // Create weak_ptr, safer than shared_ptr for lambdas std::weak_ptr<SoftwareConnection> connWeakPtr{ connection }; - auto setFixedColorCallback = [this, identifier, color, colorProperty, connWeakPtr] { + auto setFixedColorCallback = [identifier, color, colorProperty, connWeakPtr] { if (!colorProperty || connWeakPtr.expired()) return; // auto conn = connWeakPtr.lock() @@ -239,14 +445,14 @@ void PointDataMessageHandler::handleFixedColorMessage(const std::vector<char>& m addCallback(identifier, { setFixedColorCallback, {}, "handleFixedColorMessage" }); // Create and set onChange for color - auto updateColor = [this, colorProperty, identifier, connWeakPtr] { + auto updateColor = [colorProperty, identifier, connWeakPtr] { if (!colorProperty || connWeakPtr.expired()) return; onFixedColorChange(colorProperty, identifier, connWeakPtr.lock()); }; connection->addPropertySubscription(colorProperty->identifier(), identifier, updateColor); } -void PointDataMessageHandler::handleColormapMessage(const std::vector<char>& message, std::shared_ptr<SoftwareConnection> connection) { +void handleColormapMessage(const std::vector<char>& message, std::shared_ptr<SoftwareConnection> connection) { size_t messageOffset = 0; std::string identifier; @@ -285,9 +491,10 @@ void PointDataMessageHandler::handleColormapMessage(const std::vector<char>& mes auto module = global::moduleEngine->module<SoftwareIntegrationModule>(); module->storeData(identifier, storage::Key::Colormap, std::move(colorMap)); - auto colormapLimitsCallback = [this, identifier, min, max, connection] { + auto colormapLimitsCallback = [identifier, min, max, connection] { // Get renderable auto r = getRenderable(identifier); + if (!r) return; properties::Property* colormapMinProperty = r->property("ColormapMin"); // auto minPropertySub = connection->getPropertySubscription(identifier, colormapMinProperty->identifier()); @@ -324,10 +531,11 @@ void PointDataMessageHandler::handleColormapMessage(const std::vector<char>& mes }; addCallback(identifier, { colormapLimitsCallback, {}, "colormapLimitsCallback" }); - auto cmapNaNModeCallback = [this, identifier, cmapNaNMode, cmapNaNColor, connection] { + auto cmapNaNModeCallback = [identifier, cmapNaNMode, cmapNaNColor, connection] { if (cmapNaNMode == simp::NaNRenderMode::Color) { // Get renderable auto r = getRenderable(identifier); + if (!r) return; // Get cmapNaNColor of renderable properties::Property* cmapNaNColorProperty = r->property("CmapNaNColor"); @@ -355,7 +563,7 @@ void PointDataMessageHandler::handleColormapMessage(const std::vector<char>& mes }; addCallback(identifier, { cmapNaNModeCallback, {}, "cmapNaNModeCallback" }); - auto enableColormapCallback = [this, identifier] { + auto enableColormapCallback = [identifier] { global::scriptEngine->queueScript( fmt::format( "openspace.setPropertyValueSingle('Scene.{}.Renderable.ColormapEnabled', {});", @@ -369,7 +577,7 @@ void PointDataMessageHandler::handleColormapMessage(const std::vector<char>& mes addCallback(identifier, { enableColormapCallback, std::move(dataToWaitFor), "enableColormapCallback" }); } -void PointDataMessageHandler::handleAttributeDataMessage(const std::vector<char>& message, std::shared_ptr<SoftwareConnection> connection) { +void handleAttributeDataMessage(const std::vector<char>& message, std::shared_ptr<SoftwareConnection> connection) { size_t messageOffset = 0; std::string identifier; @@ -409,7 +617,7 @@ void PointDataMessageHandler::handleAttributeDataMessage(const std::vector<char> std::string callbackDescription = "handleAttributeDataMessage, key=" + storage::getStorageKeyString(key); switch (key) { case storage::Key::ColormapAttrData : { - auto callback = [this, identifier] { + auto callback = [identifier] { global::scriptEngine->queueScript( fmt::format( "openspace.setPropertyValueSingle('Scene.{}.Renderable.ColormapEnabled', {});", @@ -422,7 +630,7 @@ void PointDataMessageHandler::handleAttributeDataMessage(const std::vector<char> break; } case storage::Key::LinearSizeAttrData: { - auto callback = [this, identifier] { + auto callback = [identifier] { global::scriptEngine->queueScript( fmt::format( "openspace.setPropertyValueSingle('Scene.{}.Renderable.LinearSizeEnabled', {});", @@ -439,7 +647,7 @@ void PointDataMessageHandler::handleAttributeDataMessage(const std::vector<char> } } -void PointDataMessageHandler::handleOpacityMessage(const std::vector<char>& message, std::shared_ptr<SoftwareConnection> connection) { +void handleOpacityMessage(const std::vector<char>& message, std::shared_ptr<SoftwareConnection> connection) { size_t messageOffset = 0; std::string identifier; @@ -464,7 +672,7 @@ void PointDataMessageHandler::handleOpacityMessage(const std::vector<char>& mess // Create weak_ptr, safer than shared_ptr for lambdas std::weak_ptr<SoftwareConnection> connWeakPtr{ connection }; - auto callback = [this, identifier, opacity, opacityProperty, connWeakPtr] { + auto callback = [identifier, opacity, opacityProperty, connWeakPtr] { if (!opacityProperty || connWeakPtr.expired()) return; // auto conn = connWeakPtr.lock() @@ -490,14 +698,14 @@ void PointDataMessageHandler::handleOpacityMessage(const std::vector<char>& mess addCallback(identifier, { callback, {}, "handleOpacityMessage" }); // Create and set onChange for opacity - auto updateOpacity = [this, opacityProperty, identifier, connWeakPtr] { + auto updateOpacity = [opacityProperty, identifier, connWeakPtr] { if (!opacityProperty || connWeakPtr.expired()) return; onOpacityChange(opacityProperty, identifier, connWeakPtr.lock()); }; connection->addPropertySubscription(opacityProperty->identifier(), identifier, updateOpacity); } -void PointDataMessageHandler::handleFixedPointSizeMessage(const std::vector<char>& message, std::shared_ptr<SoftwareConnection> connection) { +void handleFixedPointSizeMessage(const std::vector<char>& message, std::shared_ptr<SoftwareConnection> connection) { size_t messageOffset = 0; std::string identifier; @@ -522,7 +730,7 @@ void PointDataMessageHandler::handleFixedPointSizeMessage(const std::vector<char // Create weak_ptr, safer than shared_ptr for lambdas std::weak_ptr<SoftwareConnection> connWeakPtr{ connection }; - auto callback = [this, identifier, size, sizeProperty, connWeakPtr] { + auto callback = [identifier, size, sizeProperty, connWeakPtr] { if (!sizeProperty || connWeakPtr.expired()) return; // auto conn = connWeakPtr.lock() @@ -556,14 +764,14 @@ void PointDataMessageHandler::handleFixedPointSizeMessage(const std::vector<char }; addCallback(identifier, { callback, {}, "handleFixedPointSizeMessage" }); - auto updateSize = [this, sizeProperty, identifier, connWeakPtr] { + auto updateSize = [sizeProperty, identifier, connWeakPtr] { if (!sizeProperty || connWeakPtr.expired()) return; onFixedPointSizeChange(sizeProperty, identifier, connWeakPtr.lock()); }; connection->addPropertySubscription(sizeProperty->identifier(), identifier, updateSize); } -void PointDataMessageHandler::handleLinearPointSizeMessage(const std::vector<char>& message, std::shared_ptr<SoftwareConnection> connection) { +void handleLinearPointSizeMessage(const std::vector<char>& message, std::shared_ptr<SoftwareConnection> connection) { size_t messageOffset = 0; std::string identifier; @@ -582,9 +790,10 @@ void PointDataMessageHandler::handleLinearPointSizeMessage(const std::vector<cha return; } - auto linearSizeCallback = [this, identifier, size, min, max] { + auto linearSizeCallback = [identifier, size, min, max] { // Get renderable auto r = getRenderable(identifier); + if (!r) return; // Get size from renderable properties::Property* sizeProperty = r->property("Size"); @@ -628,7 +837,7 @@ void PointDataMessageHandler::handleLinearPointSizeMessage(const std::vector<cha }; addCallback(identifier, { linearSizeCallback, {}, "linearSizeCallback" }); - auto enableLinearSizeCallback = [this, identifier] { + auto enableLinearSizeCallback = [identifier] { global::scriptEngine->queueScript( fmt::format( "openspace.setPropertyValueSingle('Scene.{}.Renderable.LinearSizeEnabled', {});", @@ -647,7 +856,7 @@ void PointDataMessageHandler::handleLinearPointSizeMessage(const std::vector<cha ); } -void PointDataMessageHandler::handleVisibilityMessage(const std::vector<char>& message, std::shared_ptr<SoftwareConnection> connection) { +void handleVisibilityMessage(const std::vector<char>& message, std::shared_ptr<SoftwareConnection> connection) { size_t messageOffset = 0; std::string identifier; @@ -674,7 +883,7 @@ void PointDataMessageHandler::handleVisibilityMessage(const std::vector<char>& m const bool visibility = visibilityMessage == "T"; - auto callback = [this, identifier, visibility, visibilityProperty, connWeakPtr] { + auto callback = [identifier, visibility, visibilityProperty, connWeakPtr] { if (!visibilityProperty || connWeakPtr.expired()) return; // auto conn = connWeakPtr.lock() @@ -702,14 +911,14 @@ void PointDataMessageHandler::handleVisibilityMessage(const std::vector<char>& m addCallback(identifier, { callback, {}, "handleVisibilityMessage" }); // Create and set onChange for visibility - auto toggleVisibility = [this, visibilityProperty, identifier, connWeakPtr] { + auto toggleVisibility = [visibilityProperty, identifier, connWeakPtr] { if (!visibilityProperty || connWeakPtr.expired()) return; onVisibilityChange(visibilityProperty, identifier, connWeakPtr.lock()); }; connection->addPropertySubscription(visibilityProperty->identifier(), identifier, toggleVisibility); } -void PointDataMessageHandler::handleRemoveSGNMessage(const std::vector<char>& message,std::shared_ptr<SoftwareConnection> connection) { +void handleRemoveSGNMessage(const std::vector<char>& message,std::shared_ptr<SoftwareConnection> connection) { size_t messageOffset = 0; std::string identifier; @@ -742,12 +951,95 @@ void PointDataMessageHandler::handleRemoveSGNMessage(const std::vector<char>& me LDEBUG(fmt::format("Scene graph node '{}' removed.", identifier)); } -void PointDataMessageHandler::postSync() { - std::lock_guard guard(_onceNodeExistsCallbacksMutex); +} // namespace + +void handleMessage(IncomingMessage& incomingMessage) { + if(incomingMessage.connection.expired()) { + LDEBUG(fmt::format("Trying to handle message from disconnected peer. Aborting.")); + return; + } + + auto connectionPtr = incomingMessage.connection.lock(); + + const simp::MessageType messageType = incomingMessage.type; + std::vector<char>& message = incomingMessage.content; + + switch (messageType) { + case simp::MessageType::Connection: { + LDEBUG(fmt::format("Message recieved... Connection: {}", connectionPtr->id())); + size_t offset = 0; + const std::string software = simp::readString(message, offset); + + // Send back message to software to complete handshake + connectionPtr->sendMessage(simp::formatConnectionMessage(software)); + LINFO(fmt::format("OpenSpace has connected with {} through socket", software)); + break; + } + case simp::MessageType::PointData: { + LDEBUG("Message recieved.. Point data"); + handlePointDataMessage(message, connectionPtr); + break; + } + case simp::MessageType::VelocityData: { + LDEBUG("Message recieved... Velocity data"); + handleVelocityDataMessage(message, connectionPtr); + break; + } + case simp::MessageType::RemoveSceneGraphNode: { + LDEBUG(fmt::format("Message recieved.. Remove SGN")); + handleRemoveSGNMessage(message, connectionPtr); + break; + } + case simp::MessageType::Color: { + LDEBUG(fmt::format("Message recieved.. New color")); + handleFixedColorMessage(message, connectionPtr); + break; + } + case simp::MessageType::Colormap: { + LDEBUG(fmt::format("Message recieved.. New colormap")); + handleColormapMessage(message, connectionPtr); + break; + } + case simp::MessageType::AttributeData: { + LDEBUG(fmt::format("Message recieved.. New attribute data")); + handleAttributeDataMessage(message, connectionPtr); + break; + } + case simp::MessageType::Opacity: { + LDEBUG(fmt::format("Message recieved.. New Opacity")); + handleOpacityMessage(message, connectionPtr); + break; + } + case simp::MessageType::FixedSize: { + LDEBUG(fmt::format("Message recieved.. New size")); + handleFixedPointSizeMessage(message, connectionPtr); + break; + } + case simp::MessageType::LinearSize: { + LDEBUG(fmt::format("Message recieved.. New linear size")); + handleLinearPointSizeMessage(message, connectionPtr); + break; + } + case simp::MessageType::Visibility: { + LDEBUG(fmt::format("Message recieved.. New visibility")); + handleVisibilityMessage(message, connectionPtr); + break; + } + default: { + LERROR(fmt::format( + "Unsupported message type: {}", incomingMessage.rawMessageType + )); + break; + } + } +} + +void postSyncCallbacks() { + std::lock_guard guard(callbacksMutex); // Check if the scene graph node has been created. // If so, call the corresponding callback functions to set up any subscriptions - auto callbackMapIt = _onceNodeExistsCallbacks.begin(); - while (callbackMapIt != _onceNodeExistsCallbacks.end()) { + auto callbackMapIt = callbacks.begin(); + while (callbackMapIt != callbacks.end()) { auto& [identifier, callbackList] = *callbackMapIt; try { @@ -779,225 +1071,19 @@ void PointDataMessageHandler::postSync() { } if (callbackList.empty()) { - callbackMapIt = _onceNodeExistsCallbacks.erase(callbackMapIt); - _onceNodeExistsCallbacksRetries = 0; + callbackMapIt = callbacks.erase(callbackMapIt); + callbacksRetries = 0; } else { callbackMapIt++; } } catch(std::exception &err) { - ++_onceNodeExistsCallbacksRetries; - ghoul_assert(_onceNodeExistsCallbacksRetries < 10, "Too many callback retries"); + ++callbacksRetries; + ghoul_assert(callbacksRetries < 10, "Too many callback retries"); LDEBUG(fmt::format("Error when trying to run callback: {}", err.what())); break; } } } -const Renderable* PointDataMessageHandler::getRenderable(const std::string& identifier) { - return renderable(identifier); -} - -void PointDataMessageHandler::checkRenderable( - const std::vector<char>& message, size_t& messageOffset, - std::shared_ptr<SoftwareConnection> connection, std::string& identifier -) { - std::string guiName; - - try { - // The following order of creating variables is the exact order they are received - // in the message. If the order is not the same, the global variable - // 'message offset' will be wrong - identifier = simp::readString(message, messageOffset); - guiName = simp::readString(message, messageOffset); - } - catch (const simp::SimpError& err) { - LERROR(fmt::format("Error when reading identifier and guiName from message: {}", err.message)); - return; - } - - connection->addSceneGraphNode(identifier); - - const Renderable* r = renderable(identifier); - bool hasCallbacks = false; - { - std::lock_guard guard(_onceNodeExistsCallbacksMutex); - hasCallbacks = _onceNodeExistsCallbacks.count(identifier) > 0; - } - if (!r && !hasCallbacks) { - LDEBUG(fmt::format("No renderable with identifier '{}' was found. Creating it.", identifier)); - - // Create a renderable, since it didn't exist - using namespace std::string_literals; - ghoul::Dictionary renderablePointsCloud; - renderablePointsCloud.setValue("Type", "RenderablePointsCloud"s); - renderablePointsCloud.setValue("Identifier", identifier); - renderablePointsCloud.setValue("Name", guiName); - - ghoul::Dictionary gui; - gui.setValue("Name", guiName); - gui.setValue("Path", "/Software Integration"s); - - ghoul::Dictionary node; - node.setValue("Identifier", identifier); - node.setValue("Renderable", renderablePointsCloud); - node.setValue("GUI", gui); - - global::scriptEngine->queueScript( - "openspace.addSceneGraphNode(" + ghoul::formatLua(node) + ")" - "openspace.setPropertyValueSingle('Modules.CefWebGui.Reload', nil)", // Reload WebGUI so that SoftwareIntegration GUI appears - scripting::ScriptEngine::RemoteScripting::Yes - ); - } -} - -void PointDataMessageHandler::addCallback( - const std::string& identifier, - const Callback& newCallback -) { - std::lock_guard guard(_onceNodeExistsCallbacksMutex); - auto it = _onceNodeExistsCallbacks.find(identifier); - if (it == _onceNodeExistsCallbacks.end()) { - CallbackList newCallbackList{ newCallback }; - _onceNodeExistsCallbacks.emplace(identifier, newCallbackList); - } - else { - it->second.push_back(newCallback); - } -} - -void PointDataMessageHandler::onFixedColorChange( - properties::Property* property, - const std::string& identifier, - std::shared_ptr<SoftwareConnection> connection -) { - if (!connection->isConnected()) { - SoftwareConnection::PointDataMessageHandlerFriends::removePropertySubscription( - connection, property->identifier(), identifier - ); - return; - } - - // auto propertySubscription = connection->getPropertySubscription(identifier, property->identifier()); - // if (!propertySubscription) return; - // if (!propertySubscription->shouldSendMessage) { - // propertySubscription->shouldSendMessage = true; - // return; - // } - - glm::vec4 color = std::any_cast<glm::vec4>(property->get()); - - const std::string message = simp::formatColorMessage(identifier, color); - connection->sendMessage(message); -} - -void PointDataMessageHandler::onOpacityChange( - properties::Property* property, - const std::string& identifier, - std::shared_ptr<SoftwareConnection> connection -) { - if (!connection->isConnected()) { - SoftwareConnection::PointDataMessageHandlerFriends::removePropertySubscription( - connection, property->identifier(), identifier - ); - return; - } - - // auto propertySubscription = connection->getPropertySubscription(identifier, property->identifier()); - // if (!propertySubscription) return; - // if (!propertySubscription->shouldSendMessage) { - // propertySubscription->shouldSendMessage = true; - // return; - // } - - float value = std::any_cast<float>(property->get()); - std::string hex_value = simp::floatToHex(value); - - const std::string message = simp::formatUpdateMessage(simp::MessageType::Opacity, identifier, hex_value); - connection->sendMessage(message); -} - -void PointDataMessageHandler::onFixedPointSizeChange( - properties::Property* property, - const std::string& identifier, - std::shared_ptr<SoftwareConnection> connection -) { - if (!connection->isConnected()) { - SoftwareConnection::PointDataMessageHandlerFriends::removePropertySubscription( - connection, property->identifier(), identifier - ); - return; - } - - // auto propertySubscription = connection->getPropertySubscription(identifier, property->identifier()); - // if (!propertySubscription) return; - // if (!propertySubscription->shouldSendMessage) { - // propertySubscription->shouldSendMessage = true; - // return; - // } - - float value = std::any_cast<float>(property->get()); - std::string hex_value = simp::floatToHex(value); - - const std::string message = simp::formatUpdateMessage(simp::MessageType::FixedSize, identifier, hex_value); - connection->sendMessage(message); -} - -void PointDataMessageHandler::onVisibilityChange( - properties::Property* property, - const std::string& identifier, - std::shared_ptr<SoftwareConnection> connection -) { - if (!connection->isConnected()) { - SoftwareConnection::PointDataMessageHandlerFriends::removePropertySubscription( - connection, property->identifier(), identifier - ); - return; - } - - // auto propertySubscription = connection->getPropertySubscription(identifier, property->identifier()); - // if (!propertySubscription) return; - // if (!propertySubscription->shouldSendMessage) { - // propertySubscription->shouldSendMessage = true; - // return; - // } - - bool isVisible = std::any_cast<bool>(property->get()); - std::string_view visibilityFlag = isVisible ? "T" : "F"; - - const std::string message = simp::formatUpdateMessage(simp::MessageType::Visibility, identifier, visibilityFlag); - connection->sendMessage(message); -} - -// TODO: Move to SIMP / use distanceconversion -void PointDataMessageHandler::convertToMeterPerSecond(simp::LengthUnit currLengthUnit, std::vector<float>& data) { - // distanceconversion::convertDistance - float multiplier = 1.0; - switch (currLengthUnit) { - case simp::LengthUnit::km: - multiplier = 1000.0; - break; - case simp::LengthUnit::AU: - multiplier = static_cast<float>(distanceconstants::AstronomicalUnit); - break; - case simp::LengthUnit::lyr: - multiplier = static_cast<float>(distanceconstants::LightYear); - break; - case simp::LengthUnit::pc: - multiplier = static_cast<float>(distanceconstants::Parsec); - break; - case simp::LengthUnit::kpc: - multiplier = static_cast<float>(distanceconstants::Parsec * 1.0e3); - break; - case simp::LengthUnit::Mpc: - multiplier = static_cast<float>(distanceconstants::Parsec * 1.0e6); - break; - default: - break; - } - - std::transform(std::begin(data), std::end(data), std::begin(data), - [multiplier] (float f) {return f * multiplier;}); -} - -} // namespace openspace +} // namespace openspace::softwareintegration::messagehandler diff --git a/modules/softwareintegration/messagehandler.h b/modules/softwareintegration/messagehandler.h new file mode 100644 index 000000000..47daed4bb --- /dev/null +++ b/modules/softwareintegration/messagehandler.h @@ -0,0 +1,50 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2022 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_MODULE_SOFTWAREINTEGRATION___MESSAGEHANDLER___H__ +#define __OPENSPACE_MODULE_SOFTWAREINTEGRATION___MESSAGEHANDLER___H__ + +#include <unordered_map> + +#include <openspace/properties/propertyowner.h> + +#include <modules/softwareintegration/network/softwareconnection.h> + +namespace openspace::softwareintegration::network { + +struct Callback { + std::function<void()> function; + std::vector<softwareintegration::storage::Key> waitForData = {}; + std::string description = "???"; // To help debugging. Maybe remove? +}; +using CallbackList = std::vector<Callback>; +using CallbackMap = std::unordered_map<std::string, CallbackList>; + +void postSyncCallbacks(); + +void handleMessage(IncomingMessage& incomingMessage); + +} // namespace openspace::softwareintegration::messagehandler + +#endif // __OPENSPACE_MODULE_SOFTWAREINTEGRATION___MESSAGEHANDLER___H__ diff --git a/modules/softwareintegration/network/network.cpp b/modules/softwareintegration/network/network.cpp new file mode 100644 index 000000000..84645866f --- /dev/null +++ b/modules/softwareintegration/network/network.cpp @@ -0,0 +1,132 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2022 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include <modules/softwareintegration/network/network.h> + +#include <modules/softwareintegration/messagehandler.h> +#include <modules/softwareintegration/utils.h> +#include <openspace/engine/globals.h> +#include <openspace/engine/globalscallbacks.h> +#include <openspace/scene/scene.h> +#include <openspace/scripting/scriptengine.h> +#include <ghoul/logging/logmanager.h> + + +namespace { + + constexpr const char* _loggerCat = "NetworkEngine"; + +} // namespace + +namespace openspace::softwareintegration::network { + +namespace { + +void eventLoop(std::weak_ptr<NetworkState> networkStateWeakPtr) { + while (!networkStateWeakPtr.expired()) { + auto networkState = networkStateWeakPtr.lock(); + if (networkState->shouldStopThreads) break; + // The call to "pop" below will block execution + // on this thread until interrupt is called + try { + auto pm = networkState->incomingMessages.pop(); + handleMessage(pm); + } + catch (const ghoul::RuntimeError&) { + break; + } + } +} + +void serverLoop(std::weak_ptr<NetworkState> networkStateWeakPtr) { + while (!networkStateWeakPtr.expired()) { + auto networkState = networkStateWeakPtr.lock(); + if (networkState->shouldStopThreads) break; + std::unique_ptr<ghoul::io::TcpSocket> socket = networkState->server.awaitPendingTcpSocket(); + + if (!socket) return; + + socket->startStreams(); + + auto p = std::make_shared<SoftwareConnection>(std::move(socket)); + std::lock_guard guard(networkState->softwareConnectionsMutex); + auto [it, peerInserted] = networkState->softwareConnections.emplace(p->id(), std::move(p)); + + if (peerInserted) { + auto connectionWeak = std::weak_ptr<SoftwareConnection>{ it->second }; + auto thread = std::thread{ + [connectionWeak, networkStateWeakPtr] { + connection::eventLoop(connectionWeak, networkStateWeakPtr); + } + }; + it->second->setThread(thread); + } + } +} + +} // namespace + +std::shared_ptr<NetworkState> serve(const int port) { + auto networkState = std::make_shared<NetworkState>(); + + // 4700, is the defualt port where the tcp socket will be opened to the ext. software + networkState->server.listen(port); + + std::weak_ptr<NetworkState> networkStateWeakPtr = networkState; + networkState->serverThread = std::thread{ [networkStateWeakPtr] { + serverLoop(networkStateWeakPtr); + } }; + + networkState->eventLoopThread = std::thread{ [networkStateWeakPtr] { + eventLoop(networkStateWeakPtr); + } }; + + return networkState; +}; + +void stopServer(std::shared_ptr<NetworkState> networkState) { + networkState->shouldStopThreads = true; + + networkState->incomingMessages.interrupt(); + + networkState->server.close(); + + { + std::lock_guard guardSoftwareConnections(networkState->softwareConnectionsMutex); + networkState->softwareConnections.clear(); + } + + if (networkState->serverThread.joinable()) { + networkState->serverThread.join(); + } + if (networkState->eventLoopThread.joinable()) { + networkState->eventLoopThread.join(); + } +} + +SoftwareConnectionLostError::SoftwareConnectionLostError(const std::string& msg) + : ghoul::RuntimeError(fmt::format("{}{}", "Software connection lost", msg), "SoftwareConnection") +{} + +} // namespace openspace::softwareintegration::network diff --git a/modules/softwareintegration/network/networkengine.h b/modules/softwareintegration/network/network.h similarity index 69% rename from modules/softwareintegration/network/networkengine.h rename to modules/softwareintegration/network/network.h index 7e68b14dd..13546c061 100644 --- a/modules/softwareintegration/network/networkengine.h +++ b/modules/softwareintegration/network/network.h @@ -26,54 +26,45 @@ #define __OPENSPACE_MODULE_SOFTWAREINTEGRATION___NETWORKENGINE___H__ #include <modules/softwareintegration/network/softwareconnection.h> -#include <modules/softwareintegration/pointdatamessagehandler.h> -#include <modules/softwareintegration/interruptibleconcurrentqueue.h> #include <modules/softwareintegration/utils.h> #include <ghoul/io/socket/tcpsocketserver.h> +#include <modules/softwareintegration/interruptibleconcurrentqueue.h> -namespace openspace { +#include <functional> +#include <unordered_map> -class NetworkEngine { +namespace openspace::softwareintegration::network { + +class SoftwareConnectionLostError : public ghoul::RuntimeError { public: - NetworkEngine(const int port = 4700); - ~NetworkEngine(); + explicit SoftwareConnectionLostError(const std::string& msg); +}; - struct IncomingMessage { - size_t connection_id; - SoftwareConnection::Message message{ softwareintegration::simp::MessageType::Unknown }; - }; +struct IncomingMessage { + std::weak_ptr<SoftwareConnection> connection; + softwareintegration::simp::MessageType type{ softwareintegration::simp::MessageType::Unknown }; + std::vector<char> content{}; + std::string rawMessageType{""}; +}; - void start(); - void stop(); - void postSync(); +struct NetworkState { + ghoul::io::TcpSocketServer server; -private: - void handleNewSoftwareConnections(); - void handleIncomingMessage(IncomingMessage incomingMessage); - void peerEventLoop(size_t connection_id); - void eventLoop(); + std::thread serverThread; + std::thread eventLoopThread; - // The destuction of the object a shared_ptr is pointing to, occurs when the pointer no longer has any owners - std::shared_ptr<SoftwareConnection> getSoftwareConnection(size_t id); + std::unordered_map<size_t, std::shared_ptr<SoftwareConnection>> softwareConnections{}; + std::mutex softwareConnectionsMutex{}; - std::unordered_map<size_t, std::shared_ptr<SoftwareConnection>> _softwareConnections; - std::mutex _softwareConnectionsMutex; - - ghoul::io::TcpSocketServer _socketServer; - std::thread _serverThread; - std::atomic_bool _shouldStopServerThread = false; - std::thread _eventLoopThread; - std::atomic_bool _shouldStopEventThread = false; - + std::atomic_bool shouldStopThreads{ false }; - const int _port; + InterruptibleConcurrentQueue<IncomingMessage> incomingMessages{}; +}; - // Message handlers - PointDataMessageHandler _pointDataMessageHandler; +std::shared_ptr<NetworkState> serve(const int port = 4700); - InterruptibleConcurrentQueue<IncomingMessage> _incomingMessages; -}; +void stopServer(std::shared_ptr<NetworkState> networkState); -} // namespace openspace +} // namespace openspace::softwareintegration::network #endif // __OPENSPACE_MODULE_SOFTWAREINTEGRATION___NETWORKENGINE___H__ diff --git a/modules/softwareintegration/network/networkengine.cpp b/modules/softwareintegration/network/networkengine.cpp deleted file mode 100644 index 9cade135c..000000000 --- a/modules/softwareintegration/network/networkengine.cpp +++ /dev/null @@ -1,245 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2022 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include <modules/softwareintegration/network/networkengine.h> - -#include <openspace/engine/globals.h> -#include <openspace/engine/globalscallbacks.h> -#include <openspace/scene/scene.h> -#include <openspace/scripting/scriptengine.h> -#include <ghoul/logging/logmanager.h> - - -namespace { - constexpr const char* _loggerCat = "NetworkEngine"; -} // namespace - -namespace openspace { - -using namespace softwareintegration; - -NetworkEngine::NetworkEngine(const int port) - : _port{port} -{} - -NetworkEngine::~NetworkEngine() { - stop(); -} - -void NetworkEngine::start() { - _socketServer.listen(_port); - - _serverThread = std::thread([this]() { handleNewSoftwareConnections(); }); - _eventLoopThread = std::thread([this]() { eventLoop(); }); -} - -void NetworkEngine::stop() { - _shouldStopServerThread = true; - - { - std::lock_guard guardSoftwareConnections(_softwareConnectionsMutex); - for (auto& [id, connectionPtr] : _softwareConnections) { - SoftwareConnection::NetworkEngineFriends::stopThread(connectionPtr); - } - } - - _incomingMessages.interrupt(); - - _shouldStopEventThread = true; - _socketServer.close(); - _softwareConnections.clear(); - - if (_serverThread.joinable()) { - _serverThread.join(); - } - if (_eventLoopThread.joinable()) { - _eventLoopThread.join(); - } -} - -void NetworkEngine::postSync() { - _pointDataMessageHandler.postSync(); -} - -void NetworkEngine::handleNewSoftwareConnections() { - while (!_shouldStopServerThread) { - std::unique_ptr<ghoul::io::TcpSocket> socket = _socketServer.awaitPendingTcpSocket(); - - if (!socket) return; - - socket->startStreams(); - - auto p = std::make_shared<SoftwareConnection>(std::move(socket)); - std::lock_guard guard(_softwareConnectionsMutex); - auto [it, peerInserted] = _softwareConnections.emplace(p->id(), p); - - if (peerInserted) { - auto& connectionPtr = it->second; - auto thread = std::thread{ - [this, &connectionPtr] { - peerEventLoop(connectionPtr->id()); - } - }; - connectionPtr->setThread(thread); - } - } -} - -void NetworkEngine::peerEventLoop(size_t connection_id) { - using namespace std::literals::chrono_literals; - auto connectionPtr = getSoftwareConnection(connection_id); - - while (!connectionPtr->shouldStopThread()) { - try { - SoftwareConnection::Message m = connectionPtr->receiveMessageFromSoftware(); - _incomingMessages.push({ connection_id, m }); - } - catch (const SoftwareConnection::SoftwareConnectionLostError& err) { - if (connectionPtr->shouldStopThread()) break; - - if (connectionPtr && (!connectionPtr->shouldStopThread() || !connectionPtr->isConnectedOrConnecting())) { - LDEBUG(fmt::format("Connection lost to {}: {}", connection_id, err.message)); - _incomingMessages.push({ - connection_id, - SoftwareConnection::Message{ simp::MessageType::InternalDisconnection } - }); - } - break; - } - } -} - -void NetworkEngine::eventLoop() { - while (!_shouldStopEventThread) { - // The call to "pop" below will block execution - // on this thread until interrupt is called - try { - auto pm = _incomingMessages.pop(); - handleIncomingMessage(pm); - } - catch (const ghoul::RuntimeError&) { - break; - } - } -} - -std::shared_ptr<SoftwareConnection> NetworkEngine::getSoftwareConnection(size_t id) { - std::lock_guard guard(_softwareConnectionsMutex); - auto it = _softwareConnections.find(id); - if (it == _softwareConnections.end()) return nullptr; - return it->second; -} - -void NetworkEngine::handleIncomingMessage(IncomingMessage incomingMessage) { - auto connectionPtr = getSoftwareConnection(incomingMessage.connection_id); - - if(!connectionPtr) { - LDEBUG(fmt::format("Trying to handle message from disconnected peer. Aborting.")); - return; - } - - const simp::MessageType messageType = incomingMessage.message.type; - std::vector<char>& message = incomingMessage.message.content; - - switch (messageType) { - case simp::MessageType::Connection: { - LDEBUG(fmt::format("Message recieved... Connection: {}", incomingMessage.connection_id)); - size_t offset = 0; - const std::string software = simp::readString(message, offset); - - // Send back message to software to complete handshake - connectionPtr->sendMessage(simp::formatConnectionMessage(software)); - LINFO(fmt::format("OpenSpace has connected with {} through socket", software)); - break; - } - case simp::MessageType::PointData: { - LDEBUG("Message recieved... Point data"); - _pointDataMessageHandler.handlePointDataMessage(message, connectionPtr); - break; - } - case simp::MessageType::VelocityData: { - LDEBUG("Message recieved... Velocity data"); - _pointDataMessageHandler.handleVelocityDataMessage(message, connectionPtr); - break; - } - case simp::MessageType::RemoveSceneGraphNode: { - LDEBUG(fmt::format("Message recieved... Remove SGN")); - _pointDataMessageHandler.handleRemoveSGNMessage(message, connectionPtr); - break; - } - case simp::MessageType::Color: { - LDEBUG(fmt::format("Message recieved... Color")); - _pointDataMessageHandler.handleFixedColorMessage(message, connectionPtr); - break; - } - case simp::MessageType::Colormap: { - LDEBUG(fmt::format("Message recieved... Colormap")); - _pointDataMessageHandler.handleColormapMessage(message, connectionPtr); - break; - } - case simp::MessageType::AttributeData: { - LDEBUG(fmt::format("Message recieved... Attribute data")); - _pointDataMessageHandler.handleAttributeDataMessage(message, connectionPtr); - break; - } - case simp::MessageType::Opacity: { - LDEBUG(fmt::format("Message recieved... Opacity")); - _pointDataMessageHandler.handleOpacityMessage(message, connectionPtr); - break; - } - case simp::MessageType::FixedSize: { - LDEBUG(fmt::format("Message recieved... Size")); - _pointDataMessageHandler.handleFixedPointSizeMessage(message, connectionPtr); - break; - } - case simp::MessageType::LinearSize: { - LDEBUG(fmt::format("Message recieved... Linear size")); - _pointDataMessageHandler.handleLinearPointSizeMessage(message, connectionPtr); - break; - } - case simp::MessageType::Visibility: { - LDEBUG(fmt::format("Message recieved... Visibility")); - _pointDataMessageHandler.handleVisibilityMessage(message, connectionPtr); - break; - } - case simp::MessageType::InternalDisconnection: { - LDEBUG(fmt::format("Message recieved... Disconnection from software connection: {}", incomingMessage.connection_id)); - std::lock_guard guard(_softwareConnectionsMutex); - SoftwareConnection::NetworkEngineFriends::stopThread(connectionPtr); - - if (_softwareConnections.count(incomingMessage.connection_id)) { - _softwareConnections.erase(incomingMessage.connection_id); - } - break; - } - default: { - LERROR(fmt::format( - "Unsupported message type: {}", incomingMessage.message.rawMessageType - )); - break; - } - } -} - -} // namespace openspace diff --git a/modules/softwareintegration/network/softwareconnection.cpp b/modules/softwareintegration/network/softwareconnection.cpp index d3d7d9f87..6a06f7623 100644 --- a/modules/softwareintegration/network/softwareconnection.cpp +++ b/modules/softwareintegration/network/softwareconnection.cpp @@ -2,7 +2,7 @@ * * * OpenSpace * * * - * Copyright (c) 2014-2021 * + * Copyright (c) 2014-2022 * * * * Permission is hereby granted, free of charge, to any person obtaining a copy of this * * software and associated documentation files (the "Software"), to deal in the Software * @@ -24,6 +24,7 @@ #include <modules/softwareintegration/network/softwareconnection.h> +#include <modules/softwareintegration/network/network.h> #include <ghoul/logging/logmanager.h> #include <openspace/engine/globals.h> #include <openspace/engine/syncengine.h> @@ -39,10 +40,6 @@ namespace openspace { std::atomic_size_t SoftwareConnection::_nextConnectionId = 1; -SoftwareConnection::SoftwareConnectionLostError::SoftwareConnectionLostError(const std::string& msg) - : ghoul::RuntimeError(fmt::format("{}{}", "Software connection lost", msg), "SoftwareConnection") -{} - SoftwareConnection::SoftwareConnection(std::unique_ptr<ghoul::io::TcpSocket> socket) : _id{ _nextConnectionId++ }, _socket{ std::move(socket) }, _sceneGraphNodes{}, _thread{}, _shouldStopThread{ false } @@ -52,7 +49,7 @@ SoftwareConnection::SoftwareConnection(std::unique_ptr<ghoul::io::TcpSocket> soc SoftwareConnection::SoftwareConnection(SoftwareConnection&& sc) : _id{ std::move(sc._id) }, _socket{ std::move(sc._socket) }, - _isConnected{ sc._isConnected }, _sceneGraphNodes{ std::move(sc._sceneGraphNodes) }, + _sceneGraphNodes{ std::move(sc._sceneGraphNodes) }, _thread{}, _shouldStopThread{ false } {} @@ -61,16 +58,13 @@ SoftwareConnection::~SoftwareConnection() { // destructor is called when disconnecting external // since NetworkEngine and MessageHandler has // shared_ptrs to SoftwareConnection, which can cause - // bugs if not handled properly. + // bugs if not handled properly. // Tips: use weak_ptr instead of shared_ptr in callbacks. LDEBUG(fmt::format("Removing software connection {}", _id)); - if (!_isConnected) return; - _isConnected = false; - - if (_socket) { - _socket->disconnect(); - } + _shouldStopThread = true; + _thread.detach(); + disconnect(); } void SoftwareConnection::addPropertySubscription( @@ -199,8 +193,7 @@ void SoftwareConnection::removePropertySubscriptions(const std::string& identifi _subscribedProperties.erase(propertySubscriptions); } -void SoftwareConnection::PointDataMessageHandlerFriends::removePropertySubscription( - std::shared_ptr<SoftwareConnection> connectionPtr, +void SoftwareConnection::removePropertySubscription( const std::string& propertyName, const std::string& identifier ) { @@ -224,8 +217,8 @@ void SoftwareConnection::PointDataMessageHandlerFriends::removePropertySubscript auto property = r->property(propertyName); - auto propertySubscriptions = connectionPtr->_subscribedProperties.find(identifier); - if (propertySubscriptions != connectionPtr->_subscribedProperties.end()) { + auto propertySubscriptions = _subscribedProperties.find(identifier); + if (propertySubscriptions != _subscribedProperties.end()) { // At least one property have been subscribed to on this SGN auto propertySubscription = propertySubscriptions->second.find(propertyName); if (propertySubscription != propertySubscriptions->second.end()) { @@ -246,11 +239,11 @@ void SoftwareConnection::disconnect() { } bool SoftwareConnection::isConnected() const { - return _isConnected && _socket && _socket->isConnected(); + return _socket && _socket->isConnected(); } bool SoftwareConnection::isConnectedOrConnecting() const { - return _isConnected && _socket && (_socket->isConnected() || _socket->isConnecting()); + return _socket && (_socket->isConnected() || _socket->isConnecting()); } bool SoftwareConnection::sendMessage(const std::string& message) { @@ -285,7 +278,51 @@ void SoftwareConnection::removeSceneGraphNode(const std::string& identifier) { } } -SoftwareConnection::Message SoftwareConnection::receiveMessageFromSoftware() { +size_t SoftwareConnection::id() { + return _id; +} + +void SoftwareConnection::setThread(std::thread& t) { + _thread = std::move(t); +} + +ghoul::io::TcpSocket* SoftwareConnection::socket() { + return _socket.get(); +} + +namespace softwareintegration::network::connection { + +void eventLoop( + std::weak_ptr<SoftwareConnection> connectionWeakPtr, + std::weak_ptr<NetworkState> networkStateWeakPtr +) { + while (!connectionWeakPtr.expired()) { + auto connectionPtr = connectionWeakPtr.lock(); + if (connectionPtr->_shouldStopThread) break; + + try { + IncomingMessage m = receiveMessageFromSoftware(connectionPtr); + if (networkStateWeakPtr.expired()) break; + networkStateWeakPtr.lock()->incomingMessages.push(m); + } + catch (const SoftwareConnectionLostError& err) { + if (!networkStateWeakPtr.expired() + & (!connectionPtr->_shouldStopThread || !connectionPtr->isConnectedOrConnecting()) + ) { + LDEBUG(fmt::format("Connection lost to {}: {}", connectionPtr->id(), err.message)); + auto networkState = networkStateWeakPtr.lock(); + if (networkState->softwareConnections.count(connectionPtr->id())) { + networkState->softwareConnections.erase(connectionPtr->id()); + } + } + break; + } + } +} + +IncomingMessage receiveMessageFromSoftware( + std::shared_ptr<SoftwareConnection> connectionPtr +) { // Header consists of version (3 char), message type (4 char) & subject size (15 char) size_t headerSize = 22 * sizeof(char); @@ -294,7 +331,7 @@ SoftwareConnection::Message SoftwareConnection::receiveMessageFromSoftware() { std::vector<char> subjectBuffer; // Receive the header data - if (!_socket->get(headerBuffer.data(), headerSize)) { + if (!connectionPtr->socket()->get(headerBuffer.data(), headerSize)) { throw SoftwareConnectionLostError("Failed to read header from socket. Disconnecting."); } @@ -329,34 +366,16 @@ SoftwareConnection::Message SoftwareConnection::receiveMessageFromSoftware() { auto typeEnum = softwareintegration::simp::getMessageType(type); // Receive the message data - if (typeEnum != softwareintegration::simp::MessageType::InternalDisconnection && typeEnum != softwareintegration::simp::MessageType::Unknown) { + if (typeEnum != softwareintegration::simp::MessageType::Unknown) { subjectBuffer.resize(subjectSize); - if (!_socket->get(subjectBuffer.data(), subjectSize)) { + if (!connectionPtr->socket()->get(subjectBuffer.data(), subjectSize)) { throw SoftwareConnectionLostError("Failed to read message from socket. Disconnecting."); } } - return Message{ typeEnum, subjectBuffer, type }; + return { connectionPtr, typeEnum, subjectBuffer, type }; } -bool SoftwareConnection::shouldStopThread() { - return _shouldStopThread; -} - -size_t SoftwareConnection::id() { - return _id; -} - -void SoftwareConnection::setThread(std::thread& t) { - _thread = std::move(t); -} - -void SoftwareConnection::NetworkEngineFriends::stopThread(std::shared_ptr<SoftwareConnection> connectionPtr) { - connectionPtr->_shouldStopThread = true; - connectionPtr->disconnect(); - if (connectionPtr->_thread.joinable()) { - connectionPtr->_thread.join(); - } -} +} // namespace softwareintegration::network::connection } // namespace openspace diff --git a/modules/softwareintegration/network/softwareconnection.h b/modules/softwareintegration/network/softwareconnection.h index 4de782f99..dee240acd 100644 --- a/modules/softwareintegration/network/softwareconnection.h +++ b/modules/softwareintegration/network/softwareconnection.h @@ -2,7 +2,7 @@ * * * OpenSpace * * * - * Copyright (c) 2014-2021 * + * Copyright (c) 2014-2022 * * * * Permission is hereby granted, free of charge, to any person obtaining a copy of this * * software and associated documentation files (the "Software"), to deal in the Software * @@ -25,8 +25,8 @@ #ifndef __OPENSPACE_MODULE_SOFTWAREINTEGRATION___SOFTWARECONNECTION___H__ #define __OPENSPACE_MODULE_SOFTWAREINTEGRATION___SOFTWARECONNECTION___H__ -#include <openspace/network/messagestructures.h> #include <modules/softwareintegration/utils.h> +#include <openspace/network/messagestructures.h> #include <ghoul/io/socket/tcpsocket.h> #include <openspace/properties/property.h> @@ -36,8 +36,30 @@ namespace openspace { class Renderable; +class SoftwareConnection; + +namespace softwareintegration::network { + +struct NetworkState; +struct IncomingMessage; + +namespace connection { + void eventLoop( + std::weak_ptr<SoftwareConnection> connectionWeakPtr, + std::weak_ptr<softwareintegration::network::NetworkState> networkStateWeakPtr + ); + + IncomingMessage receiveMessageFromSoftware( + std::shared_ptr<SoftwareConnection> connectionPtr + ); +} // namespace connection + +} // namespace softwareintegration::network + +using namespace softwareintegration::network; class SoftwareConnection { + public: using OnChangeHandle = properties::Property::OnChangeHandle; struct PropertySubscription { @@ -49,14 +71,6 @@ public: using Identifier = std::string; using SubscribedProperties = std::unordered_map<Identifier, PropertySubscriptions>; - struct Message { - softwareintegration::simp::MessageType type; - std::vector<char> content{}; - std::string rawMessageType{""}; - }; - - class SoftwareConnectionLostError; - explicit SoftwareConnection(std::unique_ptr<ghoul::io::TcpSocket> socket); SoftwareConnection(SoftwareConnection&& p); ~SoftwareConnection(); @@ -76,40 +90,33 @@ public: // const std::string& identifier // ); - SoftwareConnection::Message receiveMessageFromSoftware(); - void addSceneGraphNode(const std::string& identifier); void removeSceneGraphNode(const std::string& identifier); size_t id(); - size_t nConnections(); void setThread(std::thread& t); - bool shouldStopThread(); - class NetworkEngineFriends { - private: - static void stopThread(std::shared_ptr<SoftwareConnection> connectionPtr); - friend class NetworkEngine; - }; + friend void connection::eventLoop( + std::weak_ptr<SoftwareConnection> connectionWeakPtr, + std::weak_ptr<NetworkState> networkStateWeakPtr + ); - class PointDataMessageHandlerFriends { - private: - static void removePropertySubscription( - std::shared_ptr<SoftwareConnection> connectionPtr, - const std::string& propertyName, - const std::string& identifier - ); - friend class PointDataMessageHandler; - }; + friend IncomingMessage connection::receiveMessageFromSoftware( + std::shared_ptr<SoftwareConnection> connectionPtr + ); + + void removePropertySubscription(const std::string& propertyName, const std::string& identifier); -private: void removePropertySubscriptions(const std::string& identifier); + ghoul::io::TcpSocket* socket(); + +private: + SubscribedProperties _subscribedProperties; std::unordered_set<std::string> _sceneGraphNodes; - bool _isConnected = true; std::unique_ptr<ghoul::io::TcpSocket> _socket; size_t _id; @@ -119,11 +126,6 @@ private: static std::atomic_size_t _nextConnectionId; }; -class SoftwareConnection::SoftwareConnectionLostError : public ghoul::RuntimeError { -public: - explicit SoftwareConnectionLostError(const std::string& msg); -}; - } // namespace openspace #endif // __OPENSPACE_MODULE_SOFTWAREINTEGRATION___SOFTWAREINTEGRATIONMODULE___H__ diff --git a/modules/softwareintegration/pointdatamessagehandler.h b/modules/softwareintegration/pointdatamessagehandler.h deleted file mode 100644 index 5fe4cd399..000000000 --- a/modules/softwareintegration/pointdatamessagehandler.h +++ /dev/null @@ -1,106 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2021 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_SOFTWAREINTEGRATION___POINTDATAMESSAGEHANDLER___H__ -#define __OPENSPACE_MODULE_SOFTWAREINTEGRATION___POINTDATAMESSAGEHANDLER___H__ - -#include <unordered_map> - -#include <openspace/properties/propertyowner.h> - -#include <modules/softwareintegration/network/softwareconnection.h> - -namespace openspace { - -class Renderable; - -class PointDataMessageHandler { - struct Callback { - std::function<void()> function; - std::vector<softwareintegration::storage::Key> waitForData = {}; - std::string description = "???"; // To help debugging. Maybe remove? - }; - using CallbackList = std::vector<Callback>; - using CallbackMap = std::unordered_map<std::string, CallbackList>; - -public: - void handlePointDataMessage(const std::vector<char>& message, std::shared_ptr<SoftwareConnection> connection); - void handleVelocityDataMessage(const std::vector<char>& message, std::shared_ptr<SoftwareConnection> connection); - void handleFixedColorMessage(const std::vector<char>& message, std::shared_ptr<SoftwareConnection> connection); - void handleColormapMessage(const std::vector<char>& message, std::shared_ptr<SoftwareConnection> connection); - void handleAttributeDataMessage(const std::vector<char>& message, std::shared_ptr<SoftwareConnection> connection); - void handleOpacityMessage(const std::vector<char>& message, std::shared_ptr<SoftwareConnection> connection); - void handleFixedPointSizeMessage(const std::vector<char>& message, std::shared_ptr<SoftwareConnection> connection); - void handleLinearPointSizeMessage(const std::vector<char>& message, std::shared_ptr<SoftwareConnection> connection); - void handleVisibilityMessage(const std::vector<char>& message, std::shared_ptr<SoftwareConnection> connection); - void handleRemoveSGNMessage(const std::vector<char>& message, std::shared_ptr<SoftwareConnection> connection); - - void postSync(); - -private: - const Renderable* getRenderable(const std::string& identifier); - void checkRenderable( - const std::vector<char>& message, size_t& messageOffset, - std::shared_ptr<SoftwareConnection> connection, std::string& identifier - ); - - void addCallback( - const std::string& identifier, - const Callback& newCallback - ); - - CallbackMap _onceNodeExistsCallbacks; - std::mutex _onceNodeExistsCallbacksMutex; - size_t _onceNodeExistsCallbacksRetries{0}; - - void onFixedColorChange( - properties::Property* property, - const std::string& identifier, - std::shared_ptr<SoftwareConnection> connection - ); - void onOpacityChange( - properties::Property* property, - const std::string& identifier, - std::shared_ptr<SoftwareConnection> connection - ); - void onFixedPointSizeChange( - properties::Property* property, - const std::string& identifier, - std::shared_ptr<SoftwareConnection> connection - ); - void onVisibilityChange( - properties::Property* property, - const std::string& identifier, - std::shared_ptr<SoftwareConnection> connection - ); - - void convertToMeterPerSecond( - softwareintegration::simp::LengthUnit currLengthUnit, - std::vector<float>& data - ); -}; - -} // namespace openspace - -#endif // __OPENSPACE_MODULE_SOFTWAREINTEGRATION___POINTDATAMESSAGEHANDLER___H__ diff --git a/modules/softwareintegration/softwareintegrationmodule.cpp b/modules/softwareintegration/softwareintegrationmodule.cpp index 91ed0ec77..bfe2c0b2b 100644 --- a/modules/softwareintegration/softwareintegrationmodule.cpp +++ b/modules/softwareintegration/softwareintegrationmodule.cpp @@ -24,13 +24,13 @@ #include <modules/softwareintegration/softwareintegrationmodule.h> -#include <ghoul/filesystem/filesystem.h> +#include <modules/softwareintegration/rendering/renderablepointscloud.h> +#include <modules/softwareintegration/messagehandler.h> #include <ghoul/logging/logmanager.h> #include <openspace/engine/globals.h> #include <openspace/engine/syncengine.h> #include <openspace/engine/moduleengine.h> #include <openspace/scripting/scriptengine.h> -#include <modules/softwareintegration/rendering/renderablepointscloud.h> #include <openspace/documentation/documentation.h> #include <openspace/engine/globalscallbacks.h> #include <openspace/engine/windowdelegate.h> @@ -48,14 +48,9 @@ constexpr const char* _loggerCat = "SoftwareIntegrationModule"; namespace openspace { -SoftwareIntegrationModule::SoftwareIntegrationModule() : OpenSpaceModule(Name) { - if (global::windowDelegate->isMaster()) { - // The Master node will handle all communication with the external software - // and forward it to the Client nodes - // 4700, is the defualt port where the tcp socket will be opened to the ext. software - _networkEngine = std::make_unique<NetworkEngine>(); - } -} +SoftwareIntegrationModule::SoftwareIntegrationModule() + : OpenSpaceModule(Name) +{} SoftwareIntegrationModule::~SoftwareIntegrationModule() { internalDeinitialize(); @@ -89,17 +84,21 @@ void SoftwareIntegrationModule::internalInitialize(const ghoul::Dictionary&) { fRenderable->registerClass<RenderablePointsCloud>("RenderablePointsCloud"); if (global::windowDelegate->isMaster()) { - _networkEngine->start(); + // The Master node will handle all communication with the external software + // and forward it to the Client nodes + _networkState = softwareintegration::network::serve(); global::callback::postSyncPreDraw->emplace_back([this]() { - if (!_networkEngine) return; - _networkEngine->postSync(); + softwareintegration::network::postSyncCallbacks(); }); } } void SoftwareIntegrationModule::internalDeinitialize() { global::syncEngine->removeSyncables(getSyncables()); + if (_networkState) { + softwareintegration::network::stopServer(_networkState); + } } std::vector<documentation::Documentation> SoftwareIntegrationModule::documentations() const { diff --git a/modules/softwareintegration/softwareintegrationmodule.h b/modules/softwareintegration/softwareintegrationmodule.h index 411ed2249..e889f6068 100644 --- a/modules/softwareintegration/softwareintegrationmodule.h +++ b/modules/softwareintegration/softwareintegrationmodule.h @@ -26,10 +26,9 @@ #define __OPENSPACE_MODULE_SOFTWAREINTEGRATION___SOFTWAREINTEGRATIONMODULE___H__ #include <openspace/util/openspacemodule.h> - -#include <modules/softwareintegration/network/networkengine.h> #include <modules/softwareintegration/syncablefloatdatastorage.h> #include <openspace/documentation/documentation.h> +#include <modules/softwareintegration/network/network.h> namespace openspace { @@ -64,8 +63,7 @@ private: // Centralized storage for datasets SyncableFloatDataStorage _syncableFloatDataStorage; - // Network engine - std::unique_ptr<NetworkEngine> _networkEngine; + std::shared_ptr<softwareintegration::network::NetworkState> _networkState; }; } // namespace openspace diff --git a/modules/softwareintegration/utils.cpp b/modules/softwareintegration/utils.cpp index 2d76da955..90308bf9c 100644 --- a/modules/softwareintegration/utils.cpp +++ b/modules/softwareintegration/utils.cpp @@ -38,6 +38,20 @@ namespace openspace { namespace softwareintegration { namespace storage { + + // Anonymous namespace + namespace { + + const std::unordered_map<std::string, Key> _keyStringFromKey{ + { "DataPoints", Key::DataPoints }, + { "VelocityData", Key::VelocityData }, + { "Colormap", Key::Colormap }, + { "ColormapAttributeData", Key::ColormapAttrData }, + { "LinearSizeAttributeData", Key::LinearSizeAttrData }, + }; + + } // namespace + bool hasStorageKey(const std::string& key) { return _keyStringFromKey.count(key) > 0; } @@ -72,6 +86,7 @@ namespace { const std::unordered_map<std::string, MessageType> _messageTypeFromSIMPType{ { "CONN", MessageType::Connection }, { "PDAT", MessageType::PointData }, + { "VDAT", MessageType::VelocityData }, { "RSGN", MessageType::RemoveSceneGraphNode }, { "FCOL", MessageType::Color }, { "LCOL", MessageType::Colormap }, diff --git a/modules/softwareintegration/utils.h b/modules/softwareintegration/utils.h index cd6804c34..c6caa77bd 100644 --- a/modules/softwareintegration/utils.h +++ b/modules/softwareintegration/utils.h @@ -40,13 +40,6 @@ enum class Key : uint8_t { Unknown }; -const std::unordered_map<std::string, Key> _keyStringFromKey{ - { "DataPoints", Key::DataPoints }, - { "Colormap", Key::Colormap }, - { "ColormapAttributeData", Key::ColormapAttrData }, - { "LinearSizeAttributeData", Key::LinearSizeAttrData }, -}; - Key getStorageKey(const std::string& key); std::string getStorageKeyString(const Key key); @@ -73,7 +66,6 @@ enum class MessageType : uint32_t { FixedSize, LinearSize, Visibility, - InternalDisconnection, Unknown }; -- GitLab