From 0c6b5e95c641b6057018de8358bfc381fd4f84f5 Mon Sep 17 00:00:00 2001 From: Emil Axelsson Date: Fri, 4 Jan 2019 10:23:28 +0100 Subject: [PATCH 01/13] Introduce ability to configure ports etc for external applications. (#785) Introduce ability to configure ports etc for external applications, including webgui --- data/assets/util/webgui.asset | 17 +- ext/ghoul | 2 +- include/openspace/engine/configuration.h | 4 - modules/cefwebgui/cefwebguimodule.cpp | 14 +- modules/server/CMakeLists.txt | 2 + modules/server/include/connection.h | 10 +- modules/server/include/serverinterface.h | 84 ++++++ .../include/topics/authorizationtopic.h | 3 +- modules/server/servermodule.cpp | 90 ++++-- modules/server/servermodule.h | 9 +- modules/server/src/connection.cpp | 25 +- modules/server/src/serverinterface.cpp | 262 ++++++++++++++++++ .../server/src/topics/authorizationtopic.cpp | 42 +-- modules/webgui/webguimodule.cpp | 91 +++++- modules/webgui/webguimodule.h | 9 +- openspace.cfg | 37 ++- src/engine/configuration.cpp | 6 - src/engine/configuration_doc.inl | 20 -- src/network/parallelserver.cpp | 2 +- 19 files changed, 604 insertions(+), 125 deletions(-) create mode 100644 modules/server/include/serverinterface.h create mode 100644 modules/server/src/serverinterface.cpp diff --git a/data/assets/util/webgui.asset b/data/assets/util/webgui.asset index 014054fc1b..bee410ad17 100644 --- a/data/assets/util/webgui.asset +++ b/data/assets/util/webgui.asset @@ -1,8 +1,8 @@ local guiCustomization = asset.require('customization/gui') -- Select which commit hashes to use for the frontend and backend -local frontendHash = "f6db6a5dd79df1e310a75d50f8b1f97aea8a9596" -local backendHash = "3e862a67ff2869d83187ad8bda05746b583d13d4" +local frontendHash = "abf5fe23ef29af408d6c071057f1cc706c9b09a3" +local backendHash = "6e773425b3e90ba93f0090e44427e474fe5c633f" local dataProvider = "data.openspaceproject.com/files/webgui" @@ -10,7 +10,7 @@ local backend = asset.syncedResource({ Identifier = "WebGuiBackend", Name = "Web Gui Backend", Type = "UrlSynchronization", - Url = dataProvider .. "/backend/" .. backendHash .. "/backend.js" + Url = dataProvider .. "/backend/" .. backendHash .. "/backend.zip" }) local frontend = asset.syncedResource({ @@ -26,14 +26,21 @@ asset.onInitialize(function () if not openspace.directoryExists(dest) then openspace.unzipFile(frontend .. "/frontend.zip", dest, true) end + + -- Unzip the frontend bundle + dest = backend .. "/backend" + if not openspace.directoryExists(dest) then + openspace.unzipFile(backend .. "/backend.zip", dest, true) + end + -- Do not serve the files if we are in webgui development mode. -- In that case, you have to serve the webgui manually, using `npm start`. if not guiCustomization.webguiDevelopmentMode then openspace.setPropertyValueSingle( - "Modules.WebGui.ServerProcessEntryPoint", backend .. "/backend.js" + "Modules.WebGui.ServerProcessEntryPoint", backend .. "/backend/backend.js" ) openspace.setPropertyValueSingle( - "Modules.WebGui.ServerProcessWorkingDirectory", frontend .. "/frontend" + "Modules.WebGui.WebDirectory", frontend .. "/frontend" ) openspace.setPropertyValueSingle("Modules.WebGui.ServerProcessEnabled", true) end diff --git a/ext/ghoul b/ext/ghoul index 655809e25c..5e70561a05 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit 655809e25c60ad7d17141e68684eaaae0f47acc3 +Subproject commit 5e70561a05142c6bbb2484399b6816f61ce01bf7 diff --git a/include/openspace/engine/configuration.h b/include/openspace/engine/configuration.h index afa255a410..ce47681226 100644 --- a/include/openspace/engine/configuration.h +++ b/include/openspace/engine/configuration.h @@ -105,10 +105,6 @@ struct Configuration { }; OpenGLDebugContext openGLDebugContext; - std::string serverPasskey = "17308"; - bool doesRequireSocketAuthentication = true; - std::vector clientAddressWhitelist = {}; - struct HTTPProxy { bool usingHttpProxy = false; std::string address; diff --git a/modules/cefwebgui/cefwebguimodule.cpp b/modules/cefwebgui/cefwebguimodule.cpp index f600b1bf0e..6d649a95cd 100644 --- a/modules/cefwebgui/cefwebguimodule.cpp +++ b/modules/cefwebgui/cefwebguimodule.cpp @@ -22,9 +22,10 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include - #include + +#include +#include #include #include #include @@ -131,7 +132,14 @@ void CefWebGuiModule::internalInitialize(const ghoul::Dictionary& configuration) } }); - _url = configuration.value(GuiUrlInfo.identifier); + + if (configuration.hasValue(GuiUrlInfo.identifier)) { + _url = configuration.value(GuiUrlInfo.identifier); + } else { + WebGuiModule* webGuiModule = global::moduleEngine.module(); + _url = "http://localhost:" + + std::to_string(webGuiModule->port()) + "/#/onscreen"; + } _enabled = configuration.hasValue(EnabledInfo.identifier) && configuration.value(EnabledInfo.identifier); diff --git a/modules/server/CMakeLists.txt b/modules/server/CMakeLists.txt index 4c413b5ad1..08132818cc 100644 --- a/modules/server/CMakeLists.txt +++ b/modules/server/CMakeLists.txt @@ -30,6 +30,7 @@ set(HEADER_FILES include/connection.h include/connectionpool.h include/jsonconverters.h + include/serverinterface.h include/topics/authorizationtopic.h include/topics/bouncetopic.h include/topics/getpropertytopic.h @@ -49,6 +50,7 @@ set(SOURCE_FILES src/connection.cpp src/connectionpool.cpp src/jsonconverters.cpp + src/serverinterface.cpp src/topics/authorizationtopic.cpp src/topics/bouncetopic.cpp src/topics/getpropertytopic.cpp diff --git a/modules/server/include/connection.h b/modules/server/include/connection.h index 1c86f69600..b67653310a 100644 --- a/modules/server/include/connection.h +++ b/modules/server/include/connection.h @@ -41,7 +41,12 @@ class Topic; class Connection { public: - Connection(std::unique_ptr s, std::string address); + Connection( + std::unique_ptr s, + std::string address, + bool authorized = false, + const std::string& password = "" + ); void handleMessage(const std::string& message); void sendMessage(const std::string& message); @@ -62,12 +67,9 @@ private: std::thread _thread; std::string _address; - bool _requireAuthorization; bool _isAuthorized = false; std::map _messageQueue; std::map _sentMessages; - - bool isWhitelisted() const; }; } // namespace openspace diff --git a/modules/server/include/serverinterface.h b/modules/server/include/serverinterface.h new file mode 100644 index 0000000000..eeac3aacf6 --- /dev/null +++ b/modules/server/include/serverinterface.h @@ -0,0 +1,84 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2018 * + * * + * 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_SERVER___SERVERINTERFACE___H__ +#define __OPENSPACE_MODULE_SERVER___SERVERINTERFACE___H__ + +#include +#include +#include +#include +#include +#include + +namespace ghoul::io { class SocketServer; } + +namespace openspace { + +class ServerInterface : public properties::PropertyOwner { +public: + static std::unique_ptr createFromDictionary( + const ghoul::Dictionary& dictionary); + + ServerInterface(const ghoul::Dictionary& dictionary); + ~ServerInterface(); + + void initialize(); + void deinitialize(); + bool isEnabled() const; + bool isActive() const; + int port() const; + std::string password() const; + bool clientHasAccessWithoutPassword(const std::string& address) const; + bool clientIsBlocked(const std::string& address) const; + + ghoul::io::SocketServer* server(); + +private: + enum class InterfaceType : int { + TcpSocket = 0, + WebSocket + }; + + enum class Access : int { + Deny = 0, + RequirePassword, + Allow + }; + + properties::OptionProperty _type; + properties::IntProperty _port; + properties::BoolProperty _enabled; + properties::StringListProperty _allowAddresses; + properties::StringListProperty _requirePasswordAddresses; + properties::StringListProperty _denyAddresses; + properties::OptionProperty _defaultAccess; + properties::StringProperty _password; + + std::unique_ptr _socketServer; +}; + +} // namespace openspace + +#endif // __OPENSPACE_MODULE_SERVER___SERVERINTERFACE___H__ diff --git a/modules/server/include/topics/authorizationtopic.h b/modules/server/include/topics/authorizationtopic.h index 447e18d3f6..b8ae341199 100644 --- a/modules/server/include/topics/authorizationtopic.h +++ b/modules/server/include/topics/authorizationtopic.h @@ -31,7 +31,7 @@ namespace openspace { class AuthorizationTopic : public Topic { public: - AuthorizationTopic() = default; + AuthorizationTopic(std::string password); void handleJson(const nlohmann::json& json) override; bool isDone() const override; @@ -39,6 +39,7 @@ public: private: bool authorize(const std::string& key); + std::string _password; bool _isAuthenticated = false; }; diff --git a/modules/server/servermodule.cpp b/modules/server/servermodule.cpp index b488c09071..89d4cfa922 100644 --- a/modules/server/servermodule.cpp +++ b/modules/server/servermodule.cpp @@ -24,6 +24,7 @@ #include +#include #include #include #include @@ -37,53 +38,102 @@ namespace { constexpr const char* _loggerCat = "ServerModule"; + constexpr const char* KeyInterfaces = "Interfaces"; } // namespace namespace openspace { -ServerModule::ServerModule() : OpenSpaceModule(ServerModule::Name) {} +ServerModule::ServerModule() + : OpenSpaceModule(ServerModule::Name) + , _interfaceOwner({"Interfaces", "Interfaces", "Server Interfaces"}) +{ + addPropertySubOwner(_interfaceOwner); +} ServerModule::~ServerModule() { disconnectAll(); cleanUpFinishedThreads(); } -void ServerModule::internalInitialize(const ghoul::Dictionary&) { +ServerInterface* ServerModule::serverInterfaceByIdentifier(const std::string& identifier) +{ + const auto si = std::find_if( + _interfaces.begin(), + _interfaces.end(), + [identifier](std::unique_ptr& i) { + return i->identifier() == identifier; + } + ); + if (si == _interfaces.end()) { + return nullptr; + } + return si->get(); +} + +void ServerModule::internalInitialize(const ghoul::Dictionary& configuration) { using namespace ghoul::io; - std::unique_ptr tcpServer = std::make_unique(); - std::unique_ptr wsServer = std::make_unique(); + if (configuration.hasValue(KeyInterfaces)) { + ghoul::Dictionary interfaces = + configuration.value(KeyInterfaces); - // Temporary hard coded addresses and ports. - tcpServer->listen("localhost", 8000); - wsServer->listen("localhost", 8001); - LDEBUG(fmt::format( - "TCP Server listening on {}:{}",tcpServer->address(), tcpServer->port() - )); + for (std::string& key : interfaces.keys()) { + if (!interfaces.hasValue(key)) { + continue; + } + ghoul::Dictionary interfaceDictionary = + interfaces.value(key); - LDEBUG(fmt::format( - "WS Server listening on {}:{}", wsServer->address(), wsServer->port() - )); + std::unique_ptr serverInterface = + ServerInterface::createFromDictionary(interfaceDictionary); - _servers.push_back(std::move(tcpServer)); - _servers.push_back(std::move(wsServer)); + serverInterface->initialize(); + + _interfaceOwner.addPropertySubOwner(serverInterface.get()); + + if (serverInterface) { + _interfaces.push_back(std::move(serverInterface)); + } + } + + } global::callback::preSync.emplace_back([this]() { preSync(); }); } void ServerModule::preSync() { // Set up new connections. - for (std::unique_ptr& server : _servers) { + for (std::unique_ptr& serverInterface : _interfaces) { + if (!serverInterface->isEnabled()) { + continue; + } + + ghoul::io::SocketServer* socketServer = serverInterface->server(); + + if (!socketServer) { + continue; + } + std::unique_ptr socket; - while ((socket = server->nextPendingSocket())) { + while ((socket = socketServer->nextPendingSocket())) { + std::string address = socket->address(); + if (serverInterface->clientIsBlocked(address)) { + // Drop connection if the address is blocked. + continue; + } socket->startStreams(); std::shared_ptr connection = std::make_shared( std::move(socket), - server->address() + address, + false, + serverInterface->password() ); connection->setThread(std::thread( [this, connection] () { handleConnection(connection); } )); + if (serverInterface->clientHasAccessWithoutPassword(address)) { + connection->setAuthorized(true); + } _connections.push_back({ std::move(connection), false }); } } @@ -115,6 +165,10 @@ void ServerModule::cleanUpFinishedThreads() { } void ServerModule::disconnectAll() { + for (std::unique_ptr& serverInterface : _interfaces) { + serverInterface->deinitialize(); + } + for (ConnectionData& connectionData : _connections) { Connection& connection = *connectionData.connection; if (connection.socket() && connection.socket()->isConnected()) { diff --git a/modules/server/servermodule.h b/modules/server/servermodule.h index b5fec25826..529355ed47 100644 --- a/modules/server/servermodule.h +++ b/modules/server/servermodule.h @@ -27,12 +27,12 @@ #include +#include + #include #include #include -namespace ghoul::io { class SocketServer; } - namespace openspace { constexpr int SOCKET_API_VERSION_MAJOR = 0; @@ -53,6 +53,8 @@ public: ServerModule(); virtual ~ServerModule(); + ServerInterface* serverInterfaceByIdentifier(const std::string& identifier); + protected: void internalInitialize(const ghoul::Dictionary& configuration) override; @@ -72,7 +74,8 @@ private: std::deque _messageQueue; std::vector _connections; - std::vector> _servers; + std::vector> _interfaces; + properties::PropertyOwner _interfaceOwner; }; } // namespace openspace diff --git a/modules/server/src/connection.cpp b/modules/server/src/connection.cpp index 24243c857b..728afab4dd 100644 --- a/modules/server/src/connection.cpp +++ b/modules/server/src/connection.cpp @@ -64,13 +64,23 @@ namespace { namespace openspace { -Connection::Connection(std::unique_ptr s, std::string address) +Connection::Connection(std::unique_ptr s, + std::string address, + bool authorized, + const std::string& password) : _socket(std::move(s)) , _address(std::move(address)) + , _isAuthorized(authorized) { ghoul_assert(_socket, "Socket must not be nullptr"); - _topicFactory.registerClass(AuthenticationTopicKey); + _topicFactory.registerClass( + AuthenticationTopicKey, + [password](bool useDictionary, const ghoul::Dictionary& dict) { + return new AuthorizationTopic(password); + } + ); + _topicFactory.registerClass(GetPropertyTopicKey); _topicFactory.registerClass(LuaScriptTopicKey); _topicFactory.registerClass(SetPropertyTopicKey); @@ -80,9 +90,6 @@ Connection::Connection(std::unique_ptr s, std::string address _topicFactory.registerClass(TriggerPropertyTopicKey); _topicFactory.registerClass(BounceTopicKey); _topicFactory.registerClass(VersionTopicKey); - - // see if the default config for requiring auth (on) is overwritten - _requireAuthorization = global::configuration.doesRequireSocketAuthentication; } void Connection::handleMessage(const std::string& message) { @@ -186,8 +193,7 @@ void Connection::sendJson(const nlohmann::json& json) { } bool Connection::isAuthorized() const { - // require either auth to be disabled or client to be authenticated - return !_requireAuthorization || isWhitelisted() || _isAuthorized; + return _isAuthorized; } void Connection::setThread(std::thread&& thread) { @@ -206,9 +212,4 @@ void Connection::setAuthorized(bool status) { _isAuthorized = status; } -bool Connection::isWhitelisted() const { - const std::vector& wl = global::configuration.clientAddressWhitelist; - return std::find(wl.begin(), wl.end(), _address) != wl.end(); -} - } // namespace openspace diff --git a/modules/server/src/serverinterface.cpp b/modules/server/src/serverinterface.cpp new file mode 100644 index 0000000000..cbc2cadfc4 --- /dev/null +++ b/modules/server/src/serverinterface.cpp @@ -0,0 +1,262 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2018 * + * * + * 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 +#include + +#include +#include + +namespace { + + constexpr const char* KeyIdentifier = "Identifier"; + constexpr const char* TcpSocketType = "TcpSocket"; + constexpr const char* WebSocketType = "WebSocket"; + constexpr const char* DenyAccess = "Deny"; + constexpr const char* RequirePassword = "RequirePassword"; + constexpr const char* AllowAccess = "Allow"; + + constexpr openspace::properties::Property::PropertyInfo EnabledInfo = { + "Enabled", + "Is Enabled", + "This setting determines whether this server interface is enabled or not." + }; + + constexpr openspace::properties::Property::PropertyInfo TypeInfo = { + "Type", + "Type", + "Whether the interface is using a Socket or a WebSocket" + }; + + constexpr openspace::properties::Property::PropertyInfo PortInfo = { + "Port", + "Port", + "The network port to use for this sevrer interface" + }; + + constexpr openspace::properties::Property::PropertyInfo DefaultAccessInfo = { + "DefaultAccess", + "Default Access", + "Sets the default access policy: Allow, RequirePassword or Deny" + }; + + constexpr openspace::properties::Property::PropertyInfo AllowAddressesInfo = { + "AllowAddresses", + "Allow Addresses", + "Ip addresses or domains that should always be allowed access to this interface" + }; + + constexpr openspace::properties::Property::PropertyInfo RequirePasswordAddressesInfo = { + "RequirePasswordAddresses", + "Require Password Addresses", + "Ip addresses or domains that should be allowed access if they provide a password" + }; + + constexpr openspace::properties::Property::PropertyInfo DenyAddressesInfo = { + "DenyAddresses", + "Deny Addresses", + "Ip addresses or domains that should never be allowed access to this interface" + }; + + constexpr openspace::properties::Property::PropertyInfo PasswordInfo = { + "Password", + "Password", + "Password for connecting to this interface" + }; +} + +namespace openspace { + +std::unique_ptr ServerInterface::createFromDictionary( + const ghoul::Dictionary& config) +{ + // TODO: Use documentation to verify dictionary + std::unique_ptr si = std::make_unique(config); + return std::move(si); +} + +ServerInterface::ServerInterface(const ghoul::Dictionary& config) + : properties::PropertyOwner({ "", "", "" }) + , _type(TypeInfo) + , _port(PortInfo, 0) + , _defaultAccess(DefaultAccessInfo) + , _allowAddresses(AllowAddressesInfo) + , _requirePasswordAddresses(RequirePasswordAddressesInfo) + , _denyAddresses(DenyAddressesInfo) + , _enabled(EnabledInfo) + , _password(PasswordInfo) +{ + + _type.addOption(static_cast(InterfaceType::TcpSocket), TcpSocketType); + _type.addOption(static_cast(InterfaceType::WebSocket), WebSocketType); + + _defaultAccess.addOption(static_cast(Access::Deny), DenyAccess); + _defaultAccess.addOption(static_cast(Access::RequirePassword), RequirePassword); + _defaultAccess.addOption(static_cast(Access::Allow), AllowAccess); + + const std::string identifier = config.value(KeyIdentifier); + + std::function readList = + [config](const std::string& key, properties::StringListProperty& list) { + if (config.hasValue(key)) { + const ghoul::Dictionary& dict = config.value(key); + std::vector v; + for (const std::string& k : dict.keys()) { + v.push_back(dict.value(k)); + } + list.set(v); + } + }; + + readList(AllowAddressesInfo.identifier, _allowAddresses); + readList(DenyAddressesInfo.identifier, _denyAddresses); + readList(RequirePasswordAddressesInfo.identifier, _requirePasswordAddresses); + + this->setIdentifier(identifier); + this->setGuiName(identifier); + this->setDescription("Settings for server interface " + identifier); + + const std::string type = config.value(TypeInfo.identifier); + if (type == TcpSocketType) { + _type = static_cast(InterfaceType::TcpSocket); + } else if (type == WebSocketType) { + _type = static_cast(InterfaceType::WebSocket); + } + + if (config.hasValue(PasswordInfo.identifier)) { + _password = config.value(PasswordInfo.identifier); + } + + _port = static_cast(config.value(PortInfo.identifier)); + _enabled = config.value(EnabledInfo.identifier); + + std::function reinitialize = [this]() { + deinitialize(); + initialize(); + }; + + _type.onChange(reinitialize); + _port.onChange(reinitialize); + _enabled.onChange(reinitialize); + _defaultAccess.onChange(reinitialize); + _allowAddresses.onChange(reinitialize); + _requirePasswordAddresses.onChange(reinitialize); + _denyAddresses.onChange(reinitialize); + + addProperty(_type); + addProperty(_port); + addProperty(_enabled); + addProperty(_defaultAccess); + addProperty(_allowAddresses); + addProperty(_requirePasswordAddresses); + addProperty(_denyAddresses); + addProperty(_password); +} + +ServerInterface::~ServerInterface() {} + +void ServerInterface::initialize() { + if (!_enabled) { + return; + } + switch (static_cast(_type.value())) { + case InterfaceType::TcpSocket: + _socketServer = std::make_unique(); + break; + case InterfaceType::WebSocket: + _socketServer = std::make_unique(); + break; + } + _socketServer->listen(_port); +} + +void ServerInterface::deinitialize() { + _socketServer->close(); +} + +bool ServerInterface::isEnabled() const { + return _enabled.value(); +} + +bool ServerInterface::isActive() const { + return _socketServer->isListening(); +} + +int ServerInterface::port() const { + return _port; +} + +std::string ServerInterface::password() const { + return _password; +} + +bool ServerInterface::clientHasAccessWithoutPassword( + const std::string& clientAddress) const +{ + for (const std::string& address : _allowAddresses.value()) { + if (clientAddress == address) { + return true; + } + } + Access access = static_cast(_defaultAccess.value()); + if (access == Access::Allow) { + for (const std::string& address : _denyAddresses.value()) { + if (clientAddress == address) { + return false; + } + } + return true; + } + return false; +} + +bool ServerInterface::clientIsBlocked(const std::string& clientAddress) const { + for (const std::string& address : _denyAddresses.value()) { + if (clientAddress == address) { + return true; + } + } + Access access = static_cast(_defaultAccess.value()); + if (access == Access::Deny) { + for (const std::string& address : _allowAddresses.value()) { + if (clientAddress == address) { + return false; + } + } + for (const std::string& address : _requirePasswordAddresses.value()) { + if (clientAddress == address) { + return false; + } + } + return true; + } + return false; +} + +ghoul::io::SocketServer* ServerInterface::server() { + return _socketServer.get(); +} + + +} diff --git a/modules/server/src/topics/authorizationtopic.cpp b/modules/server/src/topics/authorizationtopic.cpp index d3e17b6845..3781b0cc3d 100644 --- a/modules/server/src/topics/authorizationtopic.cpp +++ b/modules/server/src/topics/authorizationtopic.cpp @@ -32,59 +32,45 @@ namespace { constexpr const char* _loggerCat = "AuthorizationTopic"; - /* https://httpstatuses.com/ */ - enum class StatusCode : int { - OK = 200, - Accepted = 202, - - BadRequest = 400, - Unauthorized = 401, - NotAcceptable = 406, - - NotImplemented = 501 - }; - - - - nlohmann::json message(const std::string& message, StatusCode statusCode) { - return { { "message", message }, { "code", static_cast(statusCode) } }; - } - + constexpr const char* KeyStatus = "status"; + constexpr const char* Authorized = "authorized"; + constexpr const char* IncorrectKey = "incorrectKey"; + constexpr const char* BadRequest = "badRequest"; } // namespace namespace openspace { +AuthorizationTopic::AuthorizationTopic(std::string password) + : _password(std::move(password)) +{} + bool AuthorizationTopic::isDone() const { return _isAuthenticated; } void AuthorizationTopic::handleJson(const nlohmann::json& json) { if (isDone()) { - _connection->sendJson(message("Already authorized.", StatusCode::OK)); + _connection->sendJson(wrappedPayload({ KeyStatus, Authorized })); } else { try { auto providedKey = json.at("key").get(); if (authorize(providedKey)) { - _connection->sendJson(message("Authorization OK.", StatusCode::Accepted)); _connection->setAuthorized(true); + _connection->sendJson(wrappedPayload({ KeyStatus, Authorized })); LINFO("Client successfully authorized."); } else { - _connection->sendJson(message("Invalid key", StatusCode::NotAcceptable)); + _connection->sendJson(wrappedPayload({ KeyStatus, IncorrectKey })); } } catch (const std::out_of_range&) { - _connection->sendJson( - message("Invalid request, key must be provided.", StatusCode::BadRequest) - ); + _connection->sendJson(wrappedPayload({ KeyStatus, BadRequest })); } catch (const std::domain_error&) { - _connection->sendJson( - message("Invalid request, invalid key format.", StatusCode::BadRequest) - ); + _connection->sendJson(wrappedPayload({ KeyStatus, BadRequest })); } } } bool AuthorizationTopic::authorize(const std::string& key) { - _isAuthenticated = (key == global::configuration.serverPasskey); + _isAuthenticated = (key == _password); return _isAuthenticated; } diff --git a/modules/webgui/webguimodule.cpp b/modules/webgui/webguimodule.cpp index 3cb740fb7d..ac5a1bcabf 100644 --- a/modules/webgui/webguimodule.cpp +++ b/modules/webgui/webguimodule.cpp @@ -24,6 +24,9 @@ #include +#include +#include +#include #include #include #include @@ -38,20 +41,41 @@ namespace { "Enable the node js based process used to serve the Web GUI." }; + constexpr openspace::properties::Property::PropertyInfo AddressInfo = { + "Address", + "Address", + "The network address to use when connecting to OpenSpace from the Web GUI." + }; + + constexpr openspace::properties::Property::PropertyInfo PortInfo = { + "Port", + "Port", + "The network port to use when serving the Web GUI over HTTP." + }; + + constexpr openspace::properties::Property::PropertyInfo WebSocketInterfaceInfo = { + "WebSocketInterface", + "WebSocket Interface", + "The identifier of the websocket interface to use when communicating." + }; + constexpr openspace::properties::Property::PropertyInfo ServerProcessEntryPointInfo = { "ServerProcessEntryPoint", "Server Process Entry Point", - "The node js command to invoke" + "The node js command to invoke." }; constexpr openspace::properties::Property::PropertyInfo - ServerProcessWorkingDirectoryInfo = + WebDirectoryInfo = { - "ServerProcessWorkingDirectory", - "Server Process Working Directory", - "The working directory of the process" + "WebDirectory", + "Web Directory", + "Directory from which to to serve static content", }; + + constexpr const char* DefaultAddress = "localhost"; + constexpr const int DefaultPort = 4680; } namespace openspace { @@ -60,14 +84,40 @@ WebGuiModule::WebGuiModule() : OpenSpaceModule(WebGuiModule::Name) , _enabled(ServerProcessEnabledInfo, false) , _entryPoint(ServerProcessEntryPointInfo) - , _workingDirectory(ServerProcessWorkingDirectoryInfo) + , _webDirectory(WebDirectoryInfo) + , _address(AddressInfo, DefaultAddress) + , _port(PortInfo, DefaultPort) + , _webSocketInterface(WebSocketInterfaceInfo, "") { addProperty(_enabled); addProperty(_entryPoint); - addProperty(_workingDirectory); + addProperty(_webDirectory); + addProperty(_address); + addProperty(_port); } -void WebGuiModule::internalInitialize(const ghoul::Dictionary&) { +int WebGuiModule::port() const { + return _port; +} + +std::string WebGuiModule::address() const { + return _address; +} + +void WebGuiModule::internalInitialize(const ghoul::Dictionary& configuration) { + if (configuration.hasValue(PortInfo.identifier)) { + _port = configuration.value(PortInfo.identifier); + } + + if (configuration.hasValue(AddressInfo.identifier)) { + _address = configuration.value(AddressInfo.identifier); + } + + if (configuration.hasValue(WebSocketInterfaceInfo.identifier)) { + _webSocketInterface = + configuration.value(WebSocketInterfaceInfo.identifier); + } + auto startOrStop = [this]() { if (_enabled) { startProcess(); @@ -85,20 +135,39 @@ void WebGuiModule::internalInitialize(const ghoul::Dictionary&) { _enabled.onChange(startOrStop); _entryPoint.onChange(restartIfEnabled); - _workingDirectory.onChange(restartIfEnabled); + _webDirectory.onChange(restartIfEnabled); + _port.onChange(restartIfEnabled); startOrStop(); } void WebGuiModule::startProcess() { + ServerModule* serverModule = global::moduleEngine.module(); + const ServerInterface* serverInterface = + serverModule->serverInterfaceByIdentifier(_webSocketInterface); + if (!serverInterface) { + LERROR("Missing server interface. Server process could not start."); + return; + } + const int webSocketPort = serverInterface->port(); + + #ifdef _MSC_VER const std::string nodePath = absPath("${MODULE_WEBGUI}/ext/nodejs/node.exe"); #else const std::string nodePath = absPath("${MODULE_WEBGUI}/ext/nodejs/node"); #endif + const std::string command = "\"" + nodePath + "\" " + + "\"" + _entryPoint.value() + "\"" + + " --directory \"" + _webDirectory.value() + "\"" + + " --http-port \"" + std::to_string(_port.value()) + "\" " + + " --ws-address \"" + _address.value() + "\"" + + " --ws-port \"" + std::to_string(webSocketPort) + "\"" + + " --auto-close --local"; + _process = std::make_unique( - "\"" + nodePath + "\" \"" + _entryPoint.value() + "\"", - _workingDirectory.value(), + command, + _webDirectory.value(), [](const char* data, size_t n) { const std::string str(data, n); LDEBUG(fmt::format("Web GUI server output: {}", str)); diff --git a/modules/webgui/webguimodule.h b/modules/webgui/webguimodule.h index 1458ce6dd1..8e6de28a80 100644 --- a/modules/webgui/webguimodule.h +++ b/modules/webgui/webguimodule.h @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -38,6 +39,8 @@ class WebGuiModule : public OpenSpaceModule { public: static constexpr const char* Name = "WebGui"; WebGuiModule(); + int port() const; + std::string address() const; protected: void internalInitialize(const ghoul::Dictionary&) override; @@ -49,7 +52,11 @@ private: std::unique_ptr _process; properties::BoolProperty _enabled; properties::StringProperty _entryPoint; - properties::StringProperty _workingDirectory; + properties::StringProperty _webDirectory; + + properties::IntProperty _port; + properties::StringProperty _address; + properties::StringProperty _webSocketInterface; }; } // namespace openspace diff --git a/openspace.cfg b/openspace.cfg index 88b96514c1..5a4e163781 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -86,12 +86,41 @@ ModuleConfigurations = { "data.openspaceproject.com/request" } }, + Server = { + Interfaces = { + { + Type = "TcpSocket", + Identifier = "DefaultTcpSocketInterface", + Port = 4681, + Enabled = true, + DefaultAccess = "Deny", + AllowAddresses = {"127.0.0.1", "localhost"}, + RequirePasswordAddresses = {}, + Password = "" + }, + { + Type = "WebSocket", + Identifier = "DefaultWebSocketInterface", + Port = 4682, + Enabled = true, + DefaultAccess = "Deny", + AllowAddresses = {"127.0.0.1", "localhost"}, + RequirePasswordAddresses = {}, + Password = "" + } + } + }, WebBrowser = { Enabled = true, WebHelperLocation = "${BIN}/openspace_web_helper" }, + WebGui = { + Address = "localhost", + HttpPort = 4680, + WebSocketInterface = "DefaultWebSocketInterface" + }, CefWebGui = { - GuiUrl = "http://localhost:8080/#/onscreen/", + -- GuiUrl = "http://localhost:4680/#/onscreen/", Enabled = true, Visible = true } @@ -154,9 +183,3 @@ OpenGLDebugContext = { -- FilterSeverity = { } } --RenderingMethod = "ABuffer" -- alternative: "Framebuffer" - -ServerPasskey = "secret!" -ClientAddressWhitelist = { - "127.0.0.1", - "localhost" -} diff --git a/src/engine/configuration.cpp b/src/engine/configuration.cpp index 807322a765..3ce4aa2c1a 100644 --- a/src/engine/configuration.cpp +++ b/src/engine/configuration.cpp @@ -57,9 +57,6 @@ namespace { constexpr const char* KeyKeyboardShortcuts = "KeyboardShortcuts"; constexpr const char* KeyDocumentation = "Documentation"; constexpr const char* KeyFactoryDocumentation = "FactoryDocumentation"; - constexpr const char* KeyRequireSocketAuthentication = "RequireSocketAuthentication"; - constexpr const char* KeyServerPasskey = "ServerPasskey"; - constexpr const char* KeyClientAddressWhitelist = "ClientAddressWhitelist"; constexpr const char* KeyLicenseDocumentation = "LicenseDocumentation"; constexpr const char* KeyShutdownCountdown = "ShutdownCountdown"; constexpr const char* KeyPerSceneCache = "PerSceneCache"; @@ -294,9 +291,6 @@ void parseLuaState(Configuration& configuration) { getValue(s, KeyDisableSceneOnMaster, c.isSceneTranslationOnMasterDisabled); getValue(s, KeyDisableInGameConsole, c.isConsoleDisabled); getValue(s, KeyRenderingMethod, c.renderingMethod); - getValue(s, KeyServerPasskey, c.serverPasskey); - getValue(s, KeyRequireSocketAuthentication, c.doesRequireSocketAuthentication); - getValue(s, KeyClientAddressWhitelist, c.clientAddressWhitelist); getValue(s, KeyLogging, c.logging); getValue(s, KeyDocumentation, c.documentation); diff --git a/src/engine/configuration_doc.inl b/src/engine/configuration_doc.inl index 87cb4b12c0..2f92091b2c 100644 --- a/src/engine/configuration_doc.inl +++ b/src/engine/configuration_doc.inl @@ -209,26 +209,6 @@ documentation::Documentation Configuration::Documentation = { Optional::Yes, "All documentations that are generated at application startup." }, - { - KeyRequireSocketAuthentication, - new BoolVerifier, - Optional::Yes, - "If socket connections should be authenticated or not before they are " - "allowed to get or set information. Defaults to 'true'." - }, - { - KeyServerPasskey, - new StringVerifier, - Optional::Yes, - "Passkey to limit server access. Used to authorize incoming connections." - }, - { - KeyClientAddressWhitelist, - new StringListVerifier, - Optional::Yes, - "String containing white listed client IP addresses that won't need to be" - "authorized with the server. Space separated" - }, { KeyShutdownCountdown, new DoubleGreaterEqualVerifier(0.0), diff --git a/src/network/parallelserver.cpp b/src/network/parallelserver.cpp index f6d3d3497e..f2514f604a 100644 --- a/src/network/parallelserver.cpp +++ b/src/network/parallelserver.cpp @@ -41,7 +41,7 @@ namespace openspace { void ParallelServer::start(int port, const std::string& password, const std::string& changeHostPassword) { - _socketServer.listen("localhost", port); + _socketServer.listen(port); _passwordHash = std::hash{}(password); _changeHostPasswordHash = std::hash{}(changeHostPassword); From ebf55f3029258802083ba4b8ccb59d909dec5fda Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Tue, 8 Jan 2019 13:57:09 +0100 Subject: [PATCH 02/13] Fix issue preventing from setting multiple vector properties through a lua script --- include/openspace/properties/numericalproperty.inl | 8 +++++--- src/properties/vector/bvec2property.cpp | 3 +++ src/properties/vector/bvec3property.cpp | 3 +++ src/properties/vector/bvec4property.cpp | 3 +++ src/properties/vector/dvec2property.cpp | 5 +++-- src/properties/vector/dvec3property.cpp | 5 +++-- src/properties/vector/dvec4property.cpp | 5 +++-- src/properties/vector/ivec2property.cpp | 5 +++-- src/properties/vector/ivec3property.cpp | 5 +++-- src/properties/vector/ivec4property.cpp | 5 +++-- src/properties/vector/uvec2property.cpp | 5 +++-- src/properties/vector/uvec3property.cpp | 5 +++-- src/properties/vector/uvec4property.cpp | 5 +++-- src/properties/vector/vec2property.cpp | 5 +++-- src/properties/vector/vec3property.cpp | 4 ++-- src/properties/vector/vec4property.cpp | 5 +++-- 16 files changed, 49 insertions(+), 27 deletions(-) diff --git a/include/openspace/properties/numericalproperty.inl b/include/openspace/properties/numericalproperty.inl index 26ebb2c18f..4a6554aac1 100644 --- a/include/openspace/properties/numericalproperty.inl +++ b/include/openspace/properties/numericalproperty.inl @@ -308,8 +308,9 @@ bool NumericalProperty::setLuaValue(lua_State* state) { T value = PropertyDelegate>::template fromLuaValue( state, success ); - if (success) + if (success) { TemplateProperty::setValue(std::move(value)); + } return success; } @@ -340,8 +341,9 @@ bool NumericalProperty::setStringValue(std::string value) { T thisValue = PropertyDelegate>::template fromString( value, success ); - if (success) + if (success) { TemplateProperty::set(ghoul::any(std::move(thisValue))); + } return success; } @@ -402,7 +404,7 @@ std::string NumericalProperty::generateAdditionalJsonDescription() const { template std::string NumericalProperty::luaToJson(std::string luaValue) const { - if(luaValue[0] == '{') { + if (luaValue[0] == '{') { luaValue.replace(0, 1, "["); } if (luaValue[luaValue.size() - 1] == '}') { diff --git a/src/properties/vector/bvec2property.cpp b/src/properties/vector/bvec2property.cpp index 5c6174d64b..7000b4c199 100644 --- a/src/properties/vector/bvec2property.cpp +++ b/src/properties/vector/bvec2property.cpp @@ -50,6 +50,9 @@ glm::bvec2 fromLuaConversion(lua_State* state, bool& success) { lua_pop(state, 1); } } + + // The last accessor argument is still on the stack + lua_pop(state, 1); success = true; return result; } diff --git a/src/properties/vector/bvec3property.cpp b/src/properties/vector/bvec3property.cpp index 29d68a3a28..b99f4eab67 100644 --- a/src/properties/vector/bvec3property.cpp +++ b/src/properties/vector/bvec3property.cpp @@ -50,6 +50,9 @@ glm::bvec3 fromLuaConversion(lua_State* state, bool& success) { lua_pop(state, 1); } } + + // The last accessor argument is still on the stack + lua_pop(state, 1); success = true; return result; } diff --git a/src/properties/vector/bvec4property.cpp b/src/properties/vector/bvec4property.cpp index 01403cef12..62b5648d94 100644 --- a/src/properties/vector/bvec4property.cpp +++ b/src/properties/vector/bvec4property.cpp @@ -50,6 +50,9 @@ glm::bvec4 fromLuaConversion(lua_State* state, bool& success) { lua_pop(state, 1); } } + + // The last accessor argument is still on the stack + lua_pop(state, 1); success = true; return result; } diff --git a/src/properties/vector/dvec2property.cpp b/src/properties/vector/dvec2property.cpp index 0aef0ea0a1..1dd6a06f63 100644 --- a/src/properties/vector/dvec2property.cpp +++ b/src/properties/vector/dvec2property.cpp @@ -50,8 +50,9 @@ glm::dvec2 fromLuaConversion(lua_State* state, bool& success) { lua_pop(state, 1); } } - // The last accessor argument and the table are still on the stack - lua_pop(state, 2); + + // The last accessor argument is still on the stack + lua_pop(state, 1); success = true; return result; } diff --git a/src/properties/vector/dvec3property.cpp b/src/properties/vector/dvec3property.cpp index 172117ef4b..55ce51f39d 100644 --- a/src/properties/vector/dvec3property.cpp +++ b/src/properties/vector/dvec3property.cpp @@ -50,8 +50,9 @@ glm::dvec3 fromLuaConversion(lua_State* state, bool& success) { lua_pop(state, 1); } } - // The last accessor argument and the table are still on the stack - lua_pop(state, 2); + + // The last accessor argument is still on the stack + lua_pop(state, 1); success = true; return result; } diff --git a/src/properties/vector/dvec4property.cpp b/src/properties/vector/dvec4property.cpp index 90c9df6fe9..afd5b2170a 100644 --- a/src/properties/vector/dvec4property.cpp +++ b/src/properties/vector/dvec4property.cpp @@ -50,8 +50,9 @@ glm::dvec4 fromLuaConversion(lua_State* state, bool& success) { lua_pop(state, 1); } } - // The last accessor argument and the table are still on the stack - lua_pop(state, 2); + + // The last accessor argument is still on the stack + lua_pop(state, 1); success = true; return result; } diff --git a/src/properties/vector/ivec2property.cpp b/src/properties/vector/ivec2property.cpp index a93527eee5..2d7d55323b 100644 --- a/src/properties/vector/ivec2property.cpp +++ b/src/properties/vector/ivec2property.cpp @@ -50,8 +50,9 @@ glm::ivec2 fromLuaConversion(lua_State* state, bool& success) { lua_pop(state, 1); } } - // The last accessor argument and the table are still on the stack - lua_pop(state, 2); + + // The last accessor argument is still on the stack + lua_pop(state, 1); success = true; return result; } diff --git a/src/properties/vector/ivec3property.cpp b/src/properties/vector/ivec3property.cpp index e68954b776..b9f13aebca 100644 --- a/src/properties/vector/ivec3property.cpp +++ b/src/properties/vector/ivec3property.cpp @@ -50,8 +50,9 @@ glm::ivec3 fromLuaConversion(lua_State* state, bool& success) { lua_pop(state, 1); } } - // The last accessor argument and the table are still on the stack - lua_pop(state, 2); + + // The last accessor argument is still on the stack + lua_pop(state, 1); success = true; return result; } diff --git a/src/properties/vector/ivec4property.cpp b/src/properties/vector/ivec4property.cpp index 6c59a883f8..cf0170d2b8 100644 --- a/src/properties/vector/ivec4property.cpp +++ b/src/properties/vector/ivec4property.cpp @@ -50,8 +50,9 @@ glm::ivec4 fromLuaConversion(lua_State* state, bool& success) { lua_pop(state, 1); } } - // The last accessor argument and the table are still on the stack - lua_pop(state, 2); + + // The last accessor argument is still on the stack + lua_pop(state, 1); success = true; return result; } diff --git a/src/properties/vector/uvec2property.cpp b/src/properties/vector/uvec2property.cpp index 0ee7e97493..350c929a47 100644 --- a/src/properties/vector/uvec2property.cpp +++ b/src/properties/vector/uvec2property.cpp @@ -50,8 +50,9 @@ glm::uvec2 fromLuaConversion(lua_State* state, bool& success) { lua_pop(state, 1); } } - // The last accessor argument and the table are still on the stack - lua_pop(state, 2); + + // The last accessor argument is still on the stack + lua_pop(state, 1); success = true; return result; } diff --git a/src/properties/vector/uvec3property.cpp b/src/properties/vector/uvec3property.cpp index 92af830bd6..9ae85b445b 100644 --- a/src/properties/vector/uvec3property.cpp +++ b/src/properties/vector/uvec3property.cpp @@ -50,8 +50,9 @@ glm::uvec3 fromLuaConversion(lua_State* state, bool& success) { lua_pop(state, 1); } } - // The last accessor argument and the table are still on the stack - lua_pop(state, 2); + + // The last accessor argument is still on the stack + lua_pop(state, 1); success = true; return result; } diff --git a/src/properties/vector/uvec4property.cpp b/src/properties/vector/uvec4property.cpp index de7d2a6098..a71aeb2801 100644 --- a/src/properties/vector/uvec4property.cpp +++ b/src/properties/vector/uvec4property.cpp @@ -50,8 +50,9 @@ glm::uvec4 fromLuaConversion(lua_State* state, bool& success) { lua_pop(state, 1); } } - // The last accessor argument and the table are still on the stack - lua_pop(state, 2); + + // The last accessor argument is still on the stack + lua_pop(state, 1); success = true; return result; } diff --git a/src/properties/vector/vec2property.cpp b/src/properties/vector/vec2property.cpp index 6936639bbf..ee257c8ffa 100644 --- a/src/properties/vector/vec2property.cpp +++ b/src/properties/vector/vec2property.cpp @@ -50,8 +50,9 @@ glm::vec2 fromLuaConversion(lua_State* state, bool& success) { lua_pop(state, 1); } } - // The last accessor argument and the table are still on the stack - lua_pop(state, 2); + + // The last accessor argument is still on the stack + lua_pop(state, 1); success = true; return result; } diff --git a/src/properties/vector/vec3property.cpp b/src/properties/vector/vec3property.cpp index 603a08d587..26395dd40d 100644 --- a/src/properties/vector/vec3property.cpp +++ b/src/properties/vector/vec3property.cpp @@ -50,8 +50,8 @@ glm::vec3 fromLuaConversion(lua_State* state, bool& success) { lua_pop(state, 1); } } - // The last accessor argument and the table are still on the stack - lua_pop(state, 2); + // The last accessor argument is still on the stack + lua_pop(state, 1); success = true; return result; } diff --git a/src/properties/vector/vec4property.cpp b/src/properties/vector/vec4property.cpp index 66761481ee..554f0b922a 100644 --- a/src/properties/vector/vec4property.cpp +++ b/src/properties/vector/vec4property.cpp @@ -50,8 +50,9 @@ glm::vec4 fromLuaConversion(lua_State* state, bool& success) { lua_pop(state, 1); } } - // The last accessor argument and the table are still on the stack - lua_pop(state, 2); + + // The last accessor argument is still on the stack + lua_pop(state, 1); success = true; return result; } From be6915ecc16e1bddc8087d5f445146658daf8f86 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 10 Jan 2019 23:06:35 +0100 Subject: [PATCH 03/13] Add Lua function to query property identifiers --- src/scene/scene.cpp | 8 ++++++++ src/scene/scene_lua.inl | 45 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/src/scene/scene.cpp b/src/scene/scene.cpp index f1b9915a9c..0785604346 100644 --- a/src/scene/scene.cpp +++ b/src/scene/scene.cpp @@ -605,6 +605,14 @@ scripting::LuaLibrary Scene::luaLibrary() { "Returns the value the property, identified by " "the provided URI." }, + { + "getProperty", + &luascriptfunctions::property_getProperty, + {}, + "string", + "Returns a list of property identifiers that match the passed regular " + "expression" + }, { "loadScene", &luascriptfunctions::loadScene, diff --git a/src/scene/scene_lua.inl b/src/scene/scene_lua.inl index 964bd0989d..a7494138e3 100644 --- a/src/scene/scene_lua.inl +++ b/src/scene/scene_lua.inl @@ -401,6 +401,51 @@ int property_getValue(lua_State* L) { return 1; } +/** + * \ingroup LuaScripts + * getProperty + * Returns a list of property identifiers that match the passed regular expression + */ +int property_getProperty(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::property_getProperty"); + + std::string regex = ghoul::lua::value(L, 1); + lua_pop(L, 1); + + + // Replace all wildcards * with the correct regex (.*) + size_t startPos = regex.find("*"); + while (startPos != std::string::npos) { + regex.replace(startPos, 1, "(.*)"); + startPos += 4; // (.*) + startPos = regex.find("*", startPos); + } + + + + std::regex r(regex); + std::vector props = allProperties(); + std::vector res; + for (properties::Property* prop : props) { + // Check the regular expression for all properties + const std::string& id = prop->fullyQualifiedIdentifier(); + + if (std::regex_match(id, r)) { + res.push_back(id); + } + } + + lua_newtable(L); + int number = 1; + for (const std::string& s : res) { + lua_pushstring(L, s.c_str()); + lua_rawseti(L, -2, number); + ++number; + } + + return 1; +} + /** * \ingroup LuaScripts * getPropertyValue(string): From c7639adb1596131c4a5d75b4336aca7badd6c776 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Sat, 19 Jan 2019 14:49:31 +0100 Subject: [PATCH 04/13] Remove warnings in Clang --- ext/ghoul | 2 +- modules/gaia/rendering/octreeculler.cpp | 4 --- modules/imgui/src/gui.cpp | 8 ----- modules/server/servermodule.cpp | 1 - modules/server/src/connection.cpp | 2 +- modules/server/src/serverinterface.cpp | 10 +++--- modules/space/rendering/renderablestars.cpp | 32 +++++++++++++------ modules/webbrowser/include/browserinstance.h | 9 ++++++ modules/webbrowser/include/eventhandler.h | 9 ++++++ .../webbrowser/include/screenspacebrowser.h | 9 ++++++ .../webbrowser/include/webkeyboardhandler.h | 10 ++++++ modules/webgui/webguimodule.cpp | 2 +- 12 files changed, 68 insertions(+), 30 deletions(-) diff --git a/ext/ghoul b/ext/ghoul index 5e70561a05..f819f18803 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit 5e70561a05142c6bbb2484399b6816f61ce01bf7 +Subproject commit f819f18803cdfd479fe80e18816c0fe800b64910 diff --git a/modules/gaia/rendering/octreeculler.cpp b/modules/gaia/rendering/octreeculler.cpp index c3a28004f9..04df883c77 100644 --- a/modules/gaia/rendering/octreeculler.cpp +++ b/modules/gaia/rendering/octreeculler.cpp @@ -27,10 +27,6 @@ #include #include -namespace { - constexpr const char* _loggerCat = "OctreeCuller"; -} // namespace - namespace openspace { namespace { diff --git a/modules/imgui/src/gui.cpp b/modules/imgui/src/gui.cpp index a77a6b41cf..5070129ff7 100644 --- a/modules/imgui/src/gui.cpp +++ b/modules/imgui/src/gui.cpp @@ -95,14 +95,6 @@ namespace { "Tooltip Delay (in s)", "This value determines the delay in seconds after which the tooltip is shown." }; - - constexpr openspace::properties::Property::PropertyInfo HiddenInfo = { - "IsHidden", - "Is Hidden", - "If this value is true, all GUI items will not be rendered, regardless of their " - "status" - }; - } // namespace namespace openspace::gui { diff --git a/modules/server/servermodule.cpp b/modules/server/servermodule.cpp index 89d4cfa922..33a805b591 100644 --- a/modules/server/servermodule.cpp +++ b/modules/server/servermodule.cpp @@ -37,7 +37,6 @@ #include namespace { - constexpr const char* _loggerCat = "ServerModule"; constexpr const char* KeyInterfaces = "Interfaces"; } // namespace diff --git a/modules/server/src/connection.cpp b/modules/server/src/connection.cpp index 728afab4dd..9fdc542b78 100644 --- a/modules/server/src/connection.cpp +++ b/modules/server/src/connection.cpp @@ -76,7 +76,7 @@ Connection::Connection(std::unique_ptr s, _topicFactory.registerClass( AuthenticationTopicKey, - [password](bool useDictionary, const ghoul::Dictionary& dict) { + [password](bool, const ghoul::Dictionary&) { return new AuthorizationTopic(password); } ); diff --git a/modules/server/src/serverinterface.cpp b/modules/server/src/serverinterface.cpp index cbc2cadfc4..49b62d55b9 100644 --- a/modules/server/src/serverinterface.cpp +++ b/modules/server/src/serverinterface.cpp @@ -89,22 +89,22 @@ namespace { namespace openspace { std::unique_ptr ServerInterface::createFromDictionary( - const ghoul::Dictionary& config) + const ghoul::Dictionary& config) { // TODO: Use documentation to verify dictionary std::unique_ptr si = std::make_unique(config); - return std::move(si); + return si; } ServerInterface::ServerInterface(const ghoul::Dictionary& config) : properties::PropertyOwner({ "", "", "" }) , _type(TypeInfo) , _port(PortInfo, 0) - , _defaultAccess(DefaultAccessInfo) + , _enabled(EnabledInfo) , _allowAddresses(AllowAddressesInfo) , _requirePasswordAddresses(RequirePasswordAddressesInfo) , _denyAddresses(DenyAddressesInfo) - , _enabled(EnabledInfo) + , _defaultAccess(DefaultAccessInfo) , _password(PasswordInfo) { @@ -117,7 +117,7 @@ ServerInterface::ServerInterface(const ghoul::Dictionary& config) const std::string identifier = config.value(KeyIdentifier); - std::function readList = + auto readList = [config](const std::string& key, properties::StringListProperty& list) { if (config.hasValue(key)) { const ghoul::Dictionary& dict = config.value(key); diff --git a/modules/space/rendering/renderablestars.cpp b/modules/space/rendering/renderablestars.cpp index 2d0c9787d4..09060984cb 100644 --- a/modules/space/rendering/renderablestars.cpp +++ b/modules/space/rendering/renderablestars.cpp @@ -41,6 +41,8 @@ #include #include +#include + namespace { constexpr const char* _loggerCat = "RenderableStars"; @@ -56,27 +58,39 @@ namespace { constexpr int8_t CurrentCacheVersion = 2; - struct CommonDataLayout { + struct ColorVBOLayout { + std::array position; // (x,y,z,e) + float value; + float luminance; + float absoluteMagnitude; + }; + + struct VelocityVBOLayout { std::array position; // (x,y,z,e) float value; float luminance; float absoluteMagnitude; - }; - - struct ColorVBOLayout : public CommonDataLayout {}; - - struct VelocityVBOLayout : public CommonDataLayout { float vx; // v_x float vy; // v_y float vz; // v_z }; - struct SpeedVBOLayout : public CommonDataLayout { + struct SpeedVBOLayout { + std::array position; // (x,y,z,e) + float value; + float luminance; + float absoluteMagnitude; + float speed; }; - struct OtherDataLayout : public CommonDataLayout {}; + struct OtherDataLayout { + std::array position; // (x,y,z,e) + float value; + float luminance; + float absoluteMagnitude; + }; constexpr openspace::properties::Property::PropertyInfo SpeckFileInfo = { "SpeckFile", @@ -407,7 +421,7 @@ void RenderableStars::initializeGL() { LERROR(fmt::format("Could not find other data column {}", _queuedOtherData)); } else { - _otherDataOption = std::distance(_dataNames.begin(), it); + _otherDataOption = static_cast(std::distance(_dataNames.begin(), it)); _queuedOtherData.clear(); } } diff --git a/modules/webbrowser/include/browserinstance.h b/modules/webbrowser/include/browserinstance.h index ab6df6a94d..aa5261d3fd 100644 --- a/modules/webbrowser/include/browserinstance.h +++ b/modules/webbrowser/include/browserinstance.h @@ -30,8 +30,17 @@ #pragma warning (disable : 4100) #endif // _MSC_VER +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-parameter" +#endif // __clang__ + #include +#ifdef __clang__ +#pragma clang diagnostic pop +#endif // __clang__ + #ifdef _MSC_VER #pragma warning (pop) #endif // _MSC_VER diff --git a/modules/webbrowser/include/eventhandler.h b/modules/webbrowser/include/eventhandler.h index 16a6ba046c..eb7e0725f6 100644 --- a/modules/webbrowser/include/eventhandler.h +++ b/modules/webbrowser/include/eventhandler.h @@ -35,8 +35,17 @@ #pragma warning (disable : 4100) #endif // _MSC_VER +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-parameter" +#endif // __clang__ + #include +#ifdef __clang__ +#pragma clang diagnostic pop +#endif // __clang__ + #ifdef _MSC_VER #pragma warning (pop) #endif // _MSC_VER diff --git a/modules/webbrowser/include/screenspacebrowser.h b/modules/webbrowser/include/screenspacebrowser.h index 88010829ba..be248483b1 100644 --- a/modules/webbrowser/include/screenspacebrowser.h +++ b/modules/webbrowser/include/screenspacebrowser.h @@ -36,8 +36,17 @@ #pragma warning (disable : 4100) #endif // _MSC_VER +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-parameter" +#endif // __clang__ + #include +#ifdef __clang__ +#pragma clang diagnostic pop +#endif // __clang__ + #ifdef _MSC_VER #pragma warning (pop) #endif // _MSC_VER diff --git a/modules/webbrowser/include/webkeyboardhandler.h b/modules/webbrowser/include/webkeyboardhandler.h index b723be63bd..2e609145a1 100644 --- a/modules/webbrowser/include/webkeyboardhandler.h +++ b/modules/webbrowser/include/webkeyboardhandler.h @@ -30,8 +30,18 @@ #pragma warning (disable : 4100) #endif // _MSC_VER + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-parameter" +#endif // __clang__ + #include +#ifdef __clang__ +#pragma clang diagnostic pop +#endif // __clang__ + #ifdef _MSC_VER #pragma warning (pop) #endif // _MSC_VER diff --git a/modules/webgui/webguimodule.cpp b/modules/webgui/webguimodule.cpp index ac5a1bcabf..a4444272c2 100644 --- a/modules/webgui/webguimodule.cpp +++ b/modules/webgui/webguimodule.cpp @@ -85,8 +85,8 @@ WebGuiModule::WebGuiModule() , _enabled(ServerProcessEnabledInfo, false) , _entryPoint(ServerProcessEntryPointInfo) , _webDirectory(WebDirectoryInfo) - , _address(AddressInfo, DefaultAddress) , _port(PortInfo, DefaultPort) + , _address(AddressInfo, DefaultAddress) , _webSocketInterface(WebSocketInterfaceInfo, "") { addProperty(_enabled); From c3cc53f08df54ba20bc8c828e30f56777d829bd6 Mon Sep 17 00:00:00 2001 From: Emil Axelsson Date: Sat, 19 Jan 2019 19:16:56 -0500 Subject: [PATCH 05/13] Make it possible to rescale web gui --- modules/cefwebgui/cefwebguimodule.cpp | 22 +++++++++++++++++++- modules/cefwebgui/cefwebguimodule.h | 2 ++ modules/webbrowser/include/browserinstance.h | 8 +++++++ modules/webbrowser/src/browserinstance.cpp | 10 +++++++++ openspace.cfg | 1 + 5 files changed, 42 insertions(+), 1 deletion(-) diff --git a/modules/cefwebgui/cefwebguimodule.cpp b/modules/cefwebgui/cefwebguimodule.cpp index 6d649a95cd..74478683e2 100644 --- a/modules/cefwebgui/cefwebguimodule.cpp +++ b/modules/cefwebgui/cefwebguimodule.cpp @@ -57,6 +57,12 @@ namespace { "GUI URL", "The URL of the webpage that is used to load the WebGUI from." }; + + constexpr openspace::properties::Property::PropertyInfo GuiScaleInfo = { + "GuiScale", + "Gui Scale", + "GUI scale multiplier." + }; } // namespace namespace openspace { @@ -66,10 +72,12 @@ CefWebGuiModule::CefWebGuiModule() , _enabled(EnabledInfo, true) , _visible(VisibleInfo, true) , _url(GuiUrlInfo, "") + , _guiScale(GuiScaleInfo, 1.0, 0.1, 3.0) { addProperty(_enabled); addProperty(_visible); addProperty(_url); + addProperty(_guiScale); } void CefWebGuiModule::startOrStopGui() { @@ -95,6 +103,9 @@ void CefWebGuiModule::startOrStopGui() { if (_visible) { webBrowserModule->attachEventHandler(_instance.get()); } + + _instance->setZoom(2.0); + webBrowserModule->addBrowser(_instance.get()); } else if (_instance) { _instance->close(true); @@ -124,6 +135,12 @@ void CefWebGuiModule::internalInitialize(const ghoul::Dictionary& configuration) } }); + _guiScale.onChange([this]() { + if (_instance) { + _instance->setZoom(_guiScale); + } + }); + _visible.onChange([this, webBrowserModule]() { if (_visible && _instance) { webBrowserModule->attachEventHandler(_instance.get()); @@ -132,7 +149,6 @@ void CefWebGuiModule::internalInitialize(const ghoul::Dictionary& configuration) } }); - if (configuration.hasValue(GuiUrlInfo.identifier)) { _url = configuration.value(GuiUrlInfo.identifier); } else { @@ -141,6 +157,10 @@ void CefWebGuiModule::internalInitialize(const ghoul::Dictionary& configuration) std::to_string(webGuiModule->port()) + "/#/onscreen"; } + if (configuration.hasValue(GuiScaleInfo.identifier)) { + _guiScale = configuration.value(GuiScaleInfo.identifier); + } + _enabled = configuration.hasValue(EnabledInfo.identifier) && configuration.value(EnabledInfo.identifier); diff --git a/modules/cefwebgui/cefwebguimodule.h b/modules/cefwebgui/cefwebguimodule.h index e506248c14..f2960a15bc 100644 --- a/modules/cefwebgui/cefwebguimodule.h +++ b/modules/cefwebgui/cefwebguimodule.h @@ -28,6 +28,7 @@ #include #include +#include #include namespace openspace { @@ -48,6 +49,7 @@ private: properties::BoolProperty _enabled; properties::BoolProperty _visible; properties::StringProperty _url; + properties::FloatProperty _guiScale; std::unique_ptr _instance; }; diff --git a/modules/webbrowser/include/browserinstance.h b/modules/webbrowser/include/browserinstance.h index aa5261d3fd..99457043e9 100644 --- a/modules/webbrowser/include/browserinstance.h +++ b/modules/webbrowser/include/browserinstance.h @@ -99,6 +99,13 @@ public: * \return if this scroll should be blocked or not */ bool sendMouseWheelEvent(const CefMouseEvent& event, const glm::ivec2& delta); + + /** + * Set the browser zoom level. + * 1.0 = default, 2.0 = double, etc. + */ + void setZoom(float ratio); + void reloadBrowser(); const CefRefPtr& getBrowser() const; @@ -111,6 +118,7 @@ private: CefRefPtr _client; CefRefPtr _browser; bool _isInitialized = false; + double _zoomLevel = 1.0; }; } // namespace openspace diff --git a/modules/webbrowser/src/browserinstance.cpp b/modules/webbrowser/src/browserinstance.cpp index 9ecccc4fd1..bc92ce429a 100644 --- a/modules/webbrowser/src/browserinstance.cpp +++ b/modules/webbrowser/src/browserinstance.cpp @@ -97,6 +97,9 @@ void BrowserInstance::reshape(const glm::ivec2& windowSize) { } void BrowserInstance::draw() { + if (_zoomLevel != _browser->GetHost()->GetZoomLevel()) { + _browser->GetHost()->SetZoomLevel(_zoomLevel); + } _renderHandler->draw(); } @@ -142,6 +145,13 @@ bool BrowserInstance::sendMouseWheelEvent(const CefMouseEvent& event, return hasContent(event.x, event.y); } +void BrowserInstance::setZoom(float ratio) { + //Zooming in CEF is non-linear according to this: + //https://www.magpcss.org/ceforum/viewtopic.php?f=6&t=11491 + _zoomLevel = glm::log(static_cast(ratio))/glm::log(1.2); + _browser->GetHost()->SetZoomLevel(_zoomLevel); +} + void BrowserInstance::reloadBrowser() { _browser->Reload(); } diff --git a/openspace.cfg b/openspace.cfg index 5a4e163781..58e0446fca 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -121,6 +121,7 @@ ModuleConfigurations = { }, CefWebGui = { -- GuiUrl = "http://localhost:4680/#/onscreen/", + -- GuiScale = 2.0, Enabled = true, Visible = true } From 8b396b60288c351775f3a9ee8cb8a126c0361451 Mon Sep 17 00:00:00 2001 From: Emil Axelsson Date: Tue, 22 Jan 2019 10:53:26 +0100 Subject: [PATCH 06/13] Fix gui scale bug --- modules/cefwebgui/cefwebguimodule.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/cefwebgui/cefwebguimodule.cpp b/modules/cefwebgui/cefwebguimodule.cpp index 74478683e2..37cd95a7d1 100644 --- a/modules/cefwebgui/cefwebguimodule.cpp +++ b/modules/cefwebgui/cefwebguimodule.cpp @@ -104,7 +104,7 @@ void CefWebGuiModule::startOrStopGui() { webBrowserModule->attachEventHandler(_instance.get()); } - _instance->setZoom(2.0); + _instance->setZoom(_guiScale); webBrowserModule->addBrowser(_instance.get()); } else if (_instance) { From 7fefaca34547e46142d076986afe336d861a0165 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Wed, 23 Jan 2019 10:17:15 -0500 Subject: [PATCH 07/13] Feature/jenkins (#788) * Update Jenkinsfile * Fix compilation for OSX * Update SGCT to fix Jenkins compile issue on Ubuntu * Make OSX Jenkins build not quiet * Only build OpenSpace target on Mac --- Jenkinsfile | 4 ++-- apps/OpenSpace/ext/sgct | 2 +- ext/ghoul | 2 +- modules/server/src/serverinterface.cpp | 1 + 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 9150da5bef..19ba20659e 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -45,7 +45,7 @@ stage('Build') { node('windows') { timeout(time: 90, unit: 'MINUTES') { // We specify the workspace directory manually to reduce the path length and thus try to avoid MSB3491 on Visual Studio - ws("C:/J/O/${env.BRANCH_NAME}/${env.BUILD_ID}") { + ws("${env.JENKINS_BASE}/O/${env.BRANCH_NAME}/${env.BUILD_ID}") { deleteDir() checkout scm bat ''' @@ -79,7 +79,7 @@ stage('Build') { cd ${srcDir}/build /Applications/CMake.app/Contents/bin/cmake -G Xcode ${srcDir} .. ''' + flags + ''' - xcodebuild -quiet -parallelizeTargets -jobs 4 + xcodebuild -parallelizeTargets -jobs 4 -target OpenSpace ''' } } diff --git a/apps/OpenSpace/ext/sgct b/apps/OpenSpace/ext/sgct index 575839eae2..a29d90e30c 160000 --- a/apps/OpenSpace/ext/sgct +++ b/apps/OpenSpace/ext/sgct @@ -1 +1 @@ -Subproject commit 575839eae2a101682f3620a9842cc6fb6d11a266 +Subproject commit a29d90e30cb15359a59179c57eecef0e8a23eec5 diff --git a/ext/ghoul b/ext/ghoul index f819f18803..5e70561a05 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit f819f18803cdfd479fe80e18816c0fe800b64910 +Subproject commit 5e70561a05142c6bbb2484399b6816f61ce01bf7 diff --git a/modules/server/src/serverinterface.cpp b/modules/server/src/serverinterface.cpp index 49b62d55b9..31f0add5ec 100644 --- a/modules/server/src/serverinterface.cpp +++ b/modules/server/src/serverinterface.cpp @@ -27,6 +27,7 @@ #include #include +#include namespace { From 99a43747e1d462ec3b7d8a842aa6372f10889137 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 24 Jan 2019 16:02:58 +0100 Subject: [PATCH 08/13] Update cfitsio to fix Jenkins --- modules/fitsfilereader/ext/cfitsio | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/fitsfilereader/ext/cfitsio b/modules/fitsfilereader/ext/cfitsio index b267f17603..3b6730fd43 160000 --- a/modules/fitsfilereader/ext/cfitsio +++ b/modules/fitsfilereader/ext/cfitsio @@ -1 +1 @@ -Subproject commit b267f17603ae62fe8c59aaef6ec9709063ff01d5 +Subproject commit 3b6730fd434779a5b0260396ccf78d3548165715 From 9a31205d89e6810f15b6bf24aa11deae2fd782ea Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Fri, 25 Jan 2019 14:53:07 +0100 Subject: [PATCH 09/13] Feature/jenkins2 (#789) Build all targets on all platforms --- Jenkinsfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 19ba20659e..7dc878568d 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -36,7 +36,7 @@ stage('Build') { cd build cmake .. ''' + flags + ''' .. - make -j4 OpenSpace + make -j4 OpenSpace GhoulTest OpenSpaceTest ''' } } @@ -54,7 +54,7 @@ stage('Build') { cd build cmake -G "Visual Studio 15 2017 Win64" .. ''' + flags + ''' .. - msbuild.exe OpenSpace.sln /nologo /verbosity:minimal /p:Configuration=Debug /target:OpenSpace + msbuild.exe OpenSpace.sln /nologo /verbosity:minimal /p:Configuration=Debug /target:OpenSpace /target:"Unit Tests"\\GhoulTest /target:"Unit Tests"\\OpenSpaceTest ''' } } @@ -79,7 +79,7 @@ stage('Build') { cd ${srcDir}/build /Applications/CMake.app/Contents/bin/cmake -G Xcode ${srcDir} .. ''' + flags + ''' - xcodebuild -parallelizeTargets -jobs 4 -target OpenSpace + xcodebuild -parallelizeTargets -jobs 4 -target OpenSpace -target GhoulTest -target OpenSpaceTest ''' } } From 59b1f2b74127da5991d5e76b703f5296c997935f Mon Sep 17 00:00:00 2001 From: Emil Axelsson Date: Thu, 31 Jan 2019 13:33:19 +0100 Subject: [PATCH 10/13] GaiaStars: Fix bug with setting shader option from dictionary --- modules/gaia/rendering/renderablegaiastars.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/modules/gaia/rendering/renderablegaiastars.cpp b/modules/gaia/rendering/renderablegaiastars.cpp index ea568a0ba5..2debb39862 100644 --- a/modules/gaia/rendering/renderablegaiastars.cpp +++ b/modules/gaia/rendering/renderablegaiastars.cpp @@ -620,6 +620,9 @@ RenderableGaiaStars::RenderableGaiaStars(const ghoul::Dictionary& dictionary) #endif // __APPLE__ if (dictionary.hasKey(ShaderOptionInfo.identifier)) { + // Default shader option: + _shaderOption = gaia::ShaderOption::Billboard_VBO; + const std::string shaderOption = dictionary.value( ShaderOptionInfo.identifier ); @@ -639,7 +642,7 @@ RenderableGaiaStars::RenderableGaiaStars(const ghoul::Dictionary& dictionary) if (shaderOption == "Point_VBO") { _shaderOption = gaia::ShaderOption::Point_VBO; } - else { + else if (shaderOption == "Billboard_VBO") { _shaderOption = gaia::ShaderOption::Billboard_VBO; } } From f60371bdbccecf0681137997c0b07a48e2da4c29 Mon Sep 17 00:00:00 2001 From: Emil Axelsson Date: Mon, 4 Feb 2019 15:14:51 +0100 Subject: [PATCH 11/13] Pass on modifier keys to CEF for mouse events (#790) * Update sgct * Pass on modifier keys to CEF for mouse events --- apps/OpenSpace/ext/sgct | 2 +- apps/OpenSpace/main.cpp | 5 +++-- include/openspace/engine/globalscallbacks.h | 6 +++--- include/openspace/engine/openspaceengine.h | 2 +- modules/imgui/imguimodule.cpp | 2 +- modules/webbrowser/include/eventhandler.h | 4 ++-- modules/webbrowser/src/eventhandler.cpp | 14 +++++++++----- src/engine/globalscallbacks.cpp | 4 ++-- src/engine/openspaceengine.cpp | 9 ++++++--- 9 files changed, 28 insertions(+), 20 deletions(-) diff --git a/apps/OpenSpace/ext/sgct b/apps/OpenSpace/ext/sgct index a29d90e30c..54f917a882 160000 --- a/apps/OpenSpace/ext/sgct +++ b/apps/OpenSpace/ext/sgct @@ -1 +1 @@ -Subproject commit a29d90e30cb15359a59179c57eecef0e8a23eec5 +Subproject commit 54f917a88203592f8b3389333a042b256ae6c9cf diff --git a/apps/OpenSpace/main.cpp b/apps/OpenSpace/main.cpp index 845b9d7848..57484252fc 100644 --- a/apps/OpenSpace/main.cpp +++ b/apps/OpenSpace/main.cpp @@ -548,11 +548,12 @@ void mainKeyboardCallback(int key, int, int action, int mods) { -void mainMouseButtonCallback(int key, int action) { +void mainMouseButtonCallback(int key, int action, int modifiers) { LTRACE("main::mainMouseButtonCallback(begin)"); openspace::global::openSpaceEngine.mouseButtonCallback( openspace::MouseButton(key), - openspace::MouseAction(action) + openspace::MouseAction(action), + openspace::KeyModifier(modifiers) ); LTRACE("main::mainMouseButtonCallback(end)"); } diff --git a/include/openspace/engine/globalscallbacks.h b/include/openspace/engine/globalscallbacks.h index 59f3d22e5d..414a7c471b 100644 --- a/include/openspace/engine/globalscallbacks.h +++ b/include/openspace/engine/globalscallbacks.h @@ -49,7 +49,7 @@ std::vector>& gPostDraw(); std::vector>& gKeyboard(); std::vector>& gCharacter(); -std::vector>& gMouseButton(); +std::vector>& gMouseButton(); std::vector>& gMousePosition(); std::vector>& gMouseScrollWheel(); @@ -70,8 +70,8 @@ static std::vector>& keyboard = detail::gKeyboard(); static std::vector>& character = detail::gCharacter(); -static std::vector>& mouseButton = - detail::gMouseButton(); +static std::vector>& + mouseButton = detail::gMouseButton(); static std::vector>& mousePosition = detail::gMousePosition(); static std::vector>& mouseScrollWheel = diff --git a/include/openspace/engine/openspaceengine.h b/include/openspace/engine/openspaceengine.h index 921a658c0c..f9c9c9a204 100644 --- a/include/openspace/engine/openspaceengine.h +++ b/include/openspace/engine/openspaceengine.h @@ -76,7 +76,7 @@ public: void postDraw(); void keyboardCallback(Key key, KeyModifier mod, KeyAction action); void charCallback(unsigned int codepoint, KeyModifier modifier); - void mouseButtonCallback(MouseButton button, MouseAction action); + void mouseButtonCallback(MouseButton button, MouseAction action, KeyModifier mods); void mousePositionCallback(double x, double y); void mouseScrollWheelCallback(double posX, double posY); void externalControlCallback(const char* receivedChars, int size, int clientId); diff --git a/modules/imgui/imguimodule.cpp b/modules/imgui/imguimodule.cpp index 539199cc06..f0d38e11aa 100644 --- a/modules/imgui/imguimodule.cpp +++ b/modules/imgui/imguimodule.cpp @@ -205,7 +205,7 @@ ImGUIModule::ImGUIModule() : OpenSpaceModule(Name) { ); global::callback::mouseButton.emplace_back( - [&](MouseButton button, MouseAction action) -> bool { + [&](MouseButton button, MouseAction action, KeyModifier) -> bool { // A list of all the windows that can show up by themselves if (gui.isEnabled() || gui._performance.isEnabled() || gui._sceneProperty.isEnabled()) diff --git a/modules/webbrowser/include/eventhandler.h b/modules/webbrowser/include/eventhandler.h index eb7e0725f6..c90cf98ebc 100644 --- a/modules/webbrowser/include/eventhandler.h +++ b/modules/webbrowser/include/eventhandler.h @@ -62,7 +62,7 @@ public: void detachBrowser(); private: - bool mouseButtonCallback(MouseButton button, MouseAction action); + bool mouseButtonCallback(MouseButton button, MouseAction action, KeyModifier mods); bool mousePositionCallback(double x, double y); bool mouseWheelCallback(glm::ivec2 delta); bool charCallback(unsigned int charCode, KeyModifier modifier); @@ -82,7 +82,7 @@ private: * * \return */ - CefMouseEvent mouseEvent(); + CefMouseEvent mouseEvent(KeyModifier mods = KeyModifier::NoModifier); /** * Find the CEF key event to use for a given action. diff --git a/modules/webbrowser/src/eventhandler.cpp b/modules/webbrowser/src/eventhandler.cpp index c263e1f92d..df9b6bdc7d 100644 --- a/modules/webbrowser/src/eventhandler.cpp +++ b/modules/webbrowser/src/eventhandler.cpp @@ -125,9 +125,9 @@ void EventHandler::initialize() { } ); global::callback::mouseButton.emplace_back( - [this](MouseButton button, MouseAction action) -> bool { + [this](MouseButton button, MouseAction action, KeyModifier mods) -> bool { if (_browserInstance) { - return mouseButtonCallback(button, action); + return mouseButtonCallback(button, action, mods); } return false; } @@ -143,7 +143,10 @@ void EventHandler::initialize() { ); } -bool EventHandler::mouseButtonCallback(MouseButton button, MouseAction action) { +bool EventHandler::mouseButtonCallback(MouseButton button, + MouseAction action, + KeyModifier mods) +{ if (button != MouseButton::Left && button != MouseButton::Right) { return false; } @@ -167,7 +170,7 @@ bool EventHandler::mouseButtonCallback(MouseButton button, MouseAction action) { } return _browserInstance->sendMouseClickEvent( - mouseEvent(), + mouseEvent(mods), (button == MouseButton::Left) ? MBT_LEFT : MBT_RIGHT, !state.down, clickCount @@ -250,7 +253,7 @@ cef_key_event_type_t EventHandler::keyEventType(KeyAction action) { } } -CefMouseEvent EventHandler::mouseEvent() { +CefMouseEvent EventHandler::mouseEvent(KeyModifier mods) { CefMouseEvent event; event.x = static_cast(_mousePosition.x); event.y = static_cast(_mousePosition.y); @@ -263,6 +266,7 @@ CefMouseEvent EventHandler::mouseEvent() { event.modifiers = EVENTFLAG_RIGHT_MOUSE_BUTTON; } + event.modifiers |= static_cast(mapToCefModifiers(mods)); return event; } diff --git a/src/engine/globalscallbacks.cpp b/src/engine/globalscallbacks.cpp index 1a70f5a19b..da64e6b45e 100644 --- a/src/engine/globalscallbacks.cpp +++ b/src/engine/globalscallbacks.cpp @@ -81,8 +81,8 @@ std::vector>& gCharacter() { return g; } -std::vector>& gMouseButton() { - static std::vector> g; +std::vector>& gMouseButton() { + static std::vector> g; return g; } diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index 460135707b..078814d518 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -1180,10 +1180,13 @@ void OpenSpaceEngine::charCallback(unsigned int codepoint, KeyModifier modifier) global::luaConsole.charCallback(codepoint, modifier); } -void OpenSpaceEngine::mouseButtonCallback(MouseButton button, MouseAction action) { - using F = std::function; +void OpenSpaceEngine::mouseButtonCallback(MouseButton button, + MouseAction action, + KeyModifier mods) +{ + using F = std::function; for (const F& func : global::callback::mouseButton) { - bool isConsumed = func(button, action); + bool isConsumed = func(button, action, mods); if (isConsumed) { // If the mouse was released, we still want to forward it to the navigation // handler in order to reliably terminate a rotation or zoom. Accidentally From a1a1ee71dbdc506bf692f774016123dc70e10d75 Mon Sep 17 00:00:00 2001 From: Micah Acinapura Date: Mon, 4 Feb 2019 17:35:56 -0500 Subject: [PATCH 12/13] added res tag for gui window in spherical config --- config/spherical_mirror_gui.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/config/spherical_mirror_gui.xml b/config/spherical_mirror_gui.xml index 2da44b6241..c56123a748 100644 --- a/config/spherical_mirror_gui.xml +++ b/config/spherical_mirror_gui.xml @@ -28,6 +28,7 @@ + From 075625c22339328c5d00f81a6d5a145437661fd1 Mon Sep 17 00:00:00 2001 From: Emil Axelsson Date: Wed, 13 Feb 2019 17:08:29 +0100 Subject: [PATCH 13/13] Prevent file handles to leak into nodejs server application --- ext/ghoul | 2 +- include/openspace/util/httprequest.h | 1 + modules/webgui/webguimodule.cpp | 4 ++-- src/util/httprequest.cpp | 20 +++++++++++++++----- 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/ext/ghoul b/ext/ghoul index 5e70561a05..9c0ba27174 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit 5e70561a05142c6bbb2484399b6816f61ce01bf7 +Subproject commit 9c0ba27174ff4d05e8d053339275a72ab66111e8 diff --git a/include/openspace/util/httprequest.h b/include/openspace/util/httprequest.h index ee160c22f3..1c6013cecc 100644 --- a/include/openspace/util/httprequest.h +++ b/include/openspace/util/httprequest.h @@ -218,6 +218,7 @@ protected: size_t handleData(HttpRequest::Data d) override; static std::mutex _directoryCreationMutex; + std::atomic_bool _hasHandle = false; private: std::string _destination; diff --git a/modules/webgui/webguimodule.cpp b/modules/webgui/webguimodule.cpp index a4444272c2..0ec8e3283a 100644 --- a/modules/webgui/webguimodule.cpp +++ b/modules/webgui/webguimodule.cpp @@ -158,8 +158,8 @@ void WebGuiModule::startProcess() { #endif const std::string command = "\"" + nodePath + "\" " - + "\"" + _entryPoint.value() + "\"" + - " --directory \"" + _webDirectory.value() + "\"" + + + "\"" + absPath(_entryPoint.value()) + "\"" + + " --directory \"" + absPath(_webDirectory.value()) + "\"" + " --http-port \"" + std::to_string(_port.value()) + "\" " + " --ws-address \"" + _address.value() + "\"" + " --ws-port \"" + std::to_string(webSocketPort) + "\"" + diff --git a/src/util/httprequest.cpp b/src/util/httprequest.cpp index e49a652429..d3d0f30876 100644 --- a/src/util/httprequest.cpp +++ b/src/util/httprequest.cpp @@ -197,6 +197,7 @@ void SyncHttpDownload::download(HttpRequest::RequestOptions opt) { if (!initDownload()) { LERROR(fmt::format("Failed sync download '{}'", _httpRequest.url())); + deinitDownload(); markAsFailed(); return; } @@ -211,14 +212,15 @@ void SyncHttpDownload::download(HttpRequest::RequestOptions opt) { _httpRequest.onReadyStateChange([this](HttpRequest::ReadyState rs) { if (rs == HttpRequest::ReadyState::Success) { LTRACE(fmt::format("Finished sync download '{}'", _httpRequest.url())); + deinitDownload(); markAsSuccessful(); } else if (rs == HttpRequest::ReadyState::Fail) { LERROR(fmt::format("Failed sync download '{}'", _httpRequest.url())); + deinitDownload(); markAsFailed(); } }); _httpRequest.perform(opt); - deinitDownload(); LTRACE(fmt::format("End sync download '{}'", _httpRequest.url())); } @@ -286,21 +288,25 @@ void AsyncHttpDownload::download(HttpRequest::RequestOptions opt) { _httpRequest.onReadyStateChange([this](HttpRequest::ReadyState rs) { if (rs == HttpRequest::ReadyState::Success) { LTRACE(fmt::format("Finished async download '{}'", _httpRequest.url())); + deinitDownload(); markAsSuccessful(); } else if (rs == HttpRequest::ReadyState::Fail) { LTRACE(fmt::format("Failed async download '{}'", _httpRequest.url())); + deinitDownload(); markAsFailed(); } }); _httpRequest.perform(opt); if (!hasSucceeded()) { + deinitDownload(); markAsFailed(); } - _downloadFinishCondition.notify_all(); - deinitDownload(); + LTRACE(fmt::format("End async download '{}'", _httpRequest.url())); + + _downloadFinishCondition.notify_all(); } const std::string& AsyncHttpDownload::url() const { @@ -351,6 +357,7 @@ bool HttpFileDownload::initDownload() { } ++nCurrentFilehandles; + _hasHandle = true; _file = std::ofstream(_destination, std::ofstream::binary); if (_file.fail()) { @@ -414,8 +421,11 @@ const std::string& HttpFileDownload::destination() const { } bool HttpFileDownload::deinitDownload() { - _file.close(); - --nCurrentFilehandles; + if (_hasHandle) { + _hasHandle = false; + _file.close(); + --nCurrentFilehandles; + } return _file.good(); }