diff --git a/apps/TaskRunner/main.cpp b/apps/TaskRunner/main.cpp index 75a7b3bfc5..a83b13c327 100644 --- a/apps/TaskRunner/main.cpp +++ b/apps/TaskRunner/main.cpp @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -91,7 +92,7 @@ void performTasks(const std::string& path) { ); ProgressBar progressBar(100); auto onProgress = [&progressBar](float progress) { - progressBar.print(progress * 100); + progressBar.print(static_cast(progress * 100.f)); }; task.perform(onProgress); } @@ -145,13 +146,28 @@ int main(int argc, char** argv) { std::make_unique>(), "Scale" ); + FactoryManager::ref().addFactory( + std::make_unique>(), + "ResourceSynchronization" + ); + openspace::ConfigurationManager configuration; std::string configurationFile = configuration.findConfiguration(ConfigurationFile); configuration.loadFromFile(configurationFile); + ghoul::Dictionary moduleConfigurations; + if (configuration.hasKeyAndValue( + ConfigurationManager::KeyModuleConfigurations)) + { + configuration.getValue( + ConfigurationManager::KeyModuleConfigurations, + moduleConfigurations + ); + } + ModuleEngine moduleEngine; - moduleEngine.initialize(); + moduleEngine.initialize(moduleConfigurations); LINFO("Initialization done."); // Parse commandline arguments diff --git a/assets/keybindings/base.asset b/assets/keybindings/base.asset index b1b2132833..1e973b6a1c 100644 --- a/assets/keybindings/base.asset +++ b/assets/keybindings/base.asset @@ -1 +1,3 @@ -dofile(openspace.absPath('${SCRIPTS}/bind_common_keys.lua')); \ No newline at end of file +asset.onInitialize(function() + dofile(openspace.absPath('${SCRIPTS}/bind_common_keys.lua')); +end) \ No newline at end of file diff --git a/include/openspace/engine/configurationmanager.h b/include/openspace/engine/configurationmanager.h index 192a2a8ab0..d745789a23 100644 --- a/include/openspace/engine/configurationmanager.h +++ b/include/openspace/engine/configurationmanager.h @@ -120,8 +120,6 @@ public: static const std::string KeyRenderingMethod; /// The key that determines whether a new cache folder is used for each scene file static const std::string KeyPerSceneCache; - // The key that stores the list of urls to http resource sync repositories - static const std::string KeyHttpSynchronizationRepositories; /// The key that stores the http proxy settings for the downloadmanager static const std::string KeyHttpProxy; /// The key that stores the address of the http proxy @@ -168,6 +166,8 @@ public: /// The part of the key storing whether the loading screen should contain a progress /// bar static const std::string PartShowProgressbar; + /// The key used to specify module specific configurations + static const std::string KeyModuleConfigurations; /** diff --git a/include/openspace/engine/moduleengine.h b/include/openspace/engine/moduleengine.h index 2b750e31ab..dbab459ae5 100644 --- a/include/openspace/engine/moduleengine.h +++ b/include/openspace/engine/moduleengine.h @@ -56,7 +56,7 @@ public: * \throw ghoul::RuntimeError If two modules in the default modules have the same * name */ - void initialize(); + void initialize(const ghoul::Dictionary& moduleConfigurations); /** * Deinitializes all of the contained OpenSpaceModule%s by calling the @@ -72,7 +72,8 @@ public: * previously * \pre \p module must not be nullptr */ - void registerModule(std::unique_ptr module); + void registerModule(std::unique_ptr module, + const ghoul::Dictionary& configuration); /** * Returns a list of all registered OpenSpaceModule%s that have been registered with diff --git a/include/openspace/scene/asset.h b/include/openspace/scene/asset.h index ab57eba8a8..63b5ddf3f1 100644 --- a/include/openspace/scene/asset.h +++ b/include/openspace/scene/asset.h @@ -99,7 +99,8 @@ public: bool cancelAllSynchronizations(); bool cancelUnwantedSynchronizations(); bool restartAllSynchronizations(); - float synchronizationProgress(); + float requestedSynchronizationProgress(); + float requiredSynchronizationProgress(); // Init bool hasInitializedParent() const; diff --git a/include/openspace/util/httprequest.h b/include/openspace/util/httprequest.h index 85ab36e57a..1621b9a44a 100644 --- a/include/openspace/util/httprequest.h +++ b/include/openspace/util/httprequest.h @@ -189,6 +189,8 @@ protected: bool initDownload() override; bool deinitDownload() override; size_t handleData(HttpRequest::Data d) override; + + static std::mutex _directoryCreationMutex; private: std::string _destination; std::ofstream _file; diff --git a/include/openspace/util/openspacemodule.h b/include/openspace/util/openspacemodule.h index 97eaf3c9d0..4cdce9628f 100644 --- a/include/openspace/util/openspacemodule.h +++ b/include/openspace/util/openspacemodule.h @@ -34,9 +34,13 @@ #include #include +namespace ghoul { class Dictionary; } + namespace openspace { namespace documentation { struct Documentation; } +class ModuleEngine; + /** * This class is the base class for an OpenSpace module. A module groups functionality * into a useful granularity to be mostly used self-sufficiently. Each OpenSpaceModule @@ -61,7 +65,8 @@ public: * is set in the OpenSpaceModule constructor. This method will call the * internalInitialize method for further customization for each subclass. */ - void initialize(); + void initialize(const ModuleEngine* moduleEngine, + const ghoul::Dictionary& configuration); /** * Empty deinitialization method that will call the internalDeinitialize method for @@ -96,6 +101,12 @@ protected: */ virtual void internalInitialize(); + /** + * Customization point for each derived class. The internalInitialize method is called + * by the initiailze method. + */ + virtual void internalInitialize(const ghoul::Dictionary& configuration); + /** * Customization point for each derived class. The internalDeinitialize method is * called by the deinitialize method. @@ -107,6 +118,14 @@ protected: * path tokens. */ std::string modulePath() const; + + /** + * Returns a const pointer to the module engine + */ + const ModuleEngine* moduleEngine() const; + +private: + const ModuleEngine* _moduleEngine; }; } // namespace openspace diff --git a/include/openspace/util/resourcesynchronization.h b/include/openspace/util/resourcesynchronization.h index e4d6ac1de0..9fb5848f0a 100644 --- a/include/openspace/util/resourcesynchronization.h +++ b/include/openspace/util/resourcesynchronization.h @@ -36,6 +36,12 @@ namespace openspace { +struct SynchronizationConfiguration { + std::string syncRoot; + std::vector httpRepositories; + bool allowSynchronization; +}; + class ResourceSynchronization : public std::enable_shared_from_this { @@ -55,6 +61,7 @@ public: const ghoul::Dictionary& dictionary); ResourceSynchronization(); + void configure(std::shared_ptr config); virtual ~ResourceSynchronization(); virtual std::string directory() = 0; virtual void start() = 0; diff --git a/modules/imgui/src/guiassetcomponent.cpp b/modules/imgui/src/guiassetcomponent.cpp index 28914b631d..a98eca94c3 100644 --- a/modules/imgui/src/guiassetcomponent.cpp +++ b/modules/imgui/src/guiassetcomponent.cpp @@ -100,7 +100,7 @@ void GuiAssetComponent::renderTree(const std::shared_ptr asset if (asset->state() == Asset::State::Synchronizing) { assetText += " (" + std::to_string( - static_cast(asset->synchronizationProgress() * 100) + static_cast(asset->requiredSynchronizationProgress() * 100) ) + "%%)"; } diff --git a/modules/sync/CMakeLists.txt b/modules/sync/CMakeLists.txt index 2b3a3a413d..40ebbd585f 100644 --- a/modules/sync/CMakeLists.txt +++ b/modules/sync/CMakeLists.txt @@ -29,6 +29,7 @@ set(HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/torrentclient.h ${CMAKE_CURRENT_SOURCE_DIR}/syncs/httpsynchronization.h ${CMAKE_CURRENT_SOURCE_DIR}/syncs/torrentsynchronization.h + ${CMAKE_CURRENT_SOURCE_DIR}/tasks/syncassettask.h ) source_group("Header Files" FILES ${HEADER_FILES}) @@ -37,6 +38,7 @@ set(SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/torrentclient.cpp ${CMAKE_CURRENT_SOURCE_DIR}/syncs/httpsynchronization.cpp ${CMAKE_CURRENT_SOURCE_DIR}/syncs/torrentsynchronization.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/tasks/syncassettask.cpp ) source_group("Source Files" FILES ${SOURCE_FILES}) diff --git a/modules/sync/syncmodule.cpp b/modules/sync/syncmodule.cpp index d328f963c4..771ef65068 100644 --- a/modules/sync/syncmodule.cpp +++ b/modules/sync/syncmodule.cpp @@ -27,6 +27,8 @@ #include #include +#include + #include #include #include @@ -39,36 +41,73 @@ #include #include +namespace { + const char* KeyHttpSynchronizationRepositories = "HttpSynchronizationRepositories"; + const char* KeySynchronizationRoot = "SynchronizationRoot"; + + const char* _loggerCat = "SyncModule"; +} + namespace openspace { SyncModule::SyncModule() : OpenSpaceModule(Name) {} -void SyncModule::internalInitialize() { +void SyncModule::internalInitialize(const ghoul::Dictionary& configuration) { + + if (configuration.hasKey(KeyHttpSynchronizationRepositories)) + { + ghoul::Dictionary dictionary = configuration.value( + KeyHttpSynchronizationRepositories); + + for (std::string key : dictionary.keys()) { + _httpSynchronizationRepositories.push_back( + dictionary.value(key) + ); + } + } + + if (configuration.hasKey(KeySynchronizationRoot)) { + _synchronizationRoot = configuration.value(KeySynchronizationRoot); + } else { + LWARNING("No synchronization root specified. Resource synchronization will be disabled."); + //_synchronizationEnabled = false; + // TODO: Make it possible to disable synchronization manyally. + // Group root and enabled into a sync config object that can be passed to syncs. + } + auto fSynchronization = FactoryManager::ref().factory(); ghoul_assert(fSynchronization, "ResourceSynchronization factory was not created"); - fSynchronization->registerClass("HttpSynchronization"); - fSynchronization->registerClass("TorrentSynchronization"); - _synchronizationRoot = FileSys.absPath("${SYNC}"); - _torrentClient.initialize(); - - if (!OsEng.configurationManager().hasKey( - ConfigurationManager::KeyHttpSynchronizationRepositories)) - { - return; - } - - ghoul::Dictionary dictionary = OsEng.configurationManager().value( - ConfigurationManager::KeyHttpSynchronizationRepositories - ); - for (std::string key : dictionary.keys()) { - _httpSynchronizationRepositories.push_back( - dictionary.value(key) + fSynchronization->registerClass( + "HttpSynchronization", + [this](bool, const ghoul::Dictionary& dictionary) { + return new HttpSynchronization( + dictionary, + _synchronizationRoot, + _httpSynchronizationRepositories ); } + ); + + fSynchronization->registerClass( + "TorrentSynchronization", + [this](bool, const ghoul::Dictionary& dictionary) { + return new TorrentSynchronization( + dictionary, + _synchronizationRoot, + &_torrentClient + ); + } + ); + + auto fTask = FactoryManager::ref().factory(); + ghoul_assert(fTask, "No task factory existed"); + fTask->registerClass("SyncAssetTask"); + + _torrentClient.initialize(); } std::vector SyncModule::documentations() const { @@ -83,6 +122,10 @@ std::string SyncModule::synchronizationRoot() const return _synchronizationRoot; } +void SyncModule::addHttpSynchronizationRepository(const std::string& repository) { + _httpSynchronizationRepositories.push_back(repository); +} + std::vector SyncModule::httpSynchronizationRepositories() const { return _httpSynchronizationRepositories; } diff --git a/modules/sync/syncmodule.h b/modules/sync/syncmodule.h index 5466a4df86..f242b883d9 100644 --- a/modules/sync/syncmodule.h +++ b/modules/sync/syncmodule.h @@ -1,4 +1,4 @@ -/***************************************************************************************** +/***************************************************************************************** * * * OpenSpace * * * @@ -38,10 +38,11 @@ public: virtual ~SyncModule() = default; std::vector documentations() const override; std::string synchronizationRoot() const; + void addHttpSynchronizationRepository(const std::string& repository); std::vector httpSynchronizationRepositories() const; TorrentClient* torrentClient(); protected: - void internalInitialize() override; + void internalInitialize(const ghoul::Dictionary& configuration) override; private: TorrentClient _torrentClient; std::vector _httpSynchronizationRepositories; diff --git a/modules/sync/syncs/httpsynchronization.cpp b/modules/sync/syncs/httpsynchronization.cpp index 85aad79e05..7314a21292 100644 --- a/modules/sync/syncs/httpsynchronization.cpp +++ b/modules/sync/syncs/httpsynchronization.cpp @@ -52,8 +52,14 @@ namespace { namespace openspace { -HttpSynchronization::HttpSynchronization(const ghoul::Dictionary& dict) +HttpSynchronization::HttpSynchronization( + const ghoul::Dictionary& dict, + const std::string& synchronizationRoot, + const std::vector& synchronizationRepositories +) : openspace::ResourceSynchronization() + , _synchronizationRoot(synchronizationRoot) + , _synchronizationRepositories(synchronizationRepositories) { documentation::testSpecificationAndThrow( Documentation(), @@ -63,13 +69,6 @@ HttpSynchronization::HttpSynchronization(const ghoul::Dictionary& dict) _identifier = dict.value(KeyIdentifier); _version = static_cast(dict.value(KeyVersion)); - - // Configure synchronization based on global settings in SyncModule - // TODO: For testability and decreaing deps, make it possible to inject this instead. - // For example, allow this configuration to be done by the TemplateFactory. - const SyncModule* syncModule = OsEng.moduleEngine().module(); - _synchronizationRoot = syncModule->synchronizationRoot(); - _synchronizationRepositories = syncModule->httpSynchronizationRepositories(); } HttpSynchronization::~HttpSynchronization() { diff --git a/modules/sync/syncs/httpsynchronization.h b/modules/sync/syncs/httpsynchronization.h index 0ae89e989c..50af99c19b 100644 --- a/modules/sync/syncs/httpsynchronization.h +++ b/modules/sync/syncs/httpsynchronization.h @@ -34,7 +34,12 @@ namespace openspace { class HttpSynchronization : public ResourceSynchronization { public: - HttpSynchronization(const ghoul::Dictionary& dict); + HttpSynchronization( + const ghoul::Dictionary& dict, + const std::string& synchronizationRoot, + const std::vector& synchronizationRepositories + ); + virtual ~HttpSynchronization(); static documentation::Documentation Documentation(); @@ -54,9 +59,9 @@ private: bool hasSyncFile(); void createSyncFile(); - std::atomic_bool _nTotalBytesKnown; - std::atomic_size_t _nTotalBytes; - std::atomic_size_t _nSynchronizedBytes; + std::atomic_bool _nTotalBytesKnown = false; + std::atomic_size_t _nTotalBytes = 0; + std::atomic_size_t _nSynchronizedBytes = 0; std::atomic_bool _shouldCancel = false; std::string _identifier; diff --git a/modules/sync/syncs/torrentsynchronization.cpp b/modules/sync/syncs/torrentsynchronization.cpp index 84d27ef13d..55af204774 100644 --- a/modules/sync/syncs/torrentsynchronization.cpp +++ b/modules/sync/syncs/torrentsynchronization.cpp @@ -45,8 +45,12 @@ namespace { namespace openspace { -TorrentSynchronization::TorrentSynchronization(const ghoul::Dictionary& dict) +TorrentSynchronization::TorrentSynchronization(const ghoul::Dictionary& dict, + const std::string& synchronizationRoot, + TorrentClient* torrentClient) : openspace::ResourceSynchronization() + , _synchronizationRoot(synchronizationRoot) + , _torrentClient(torrentClient) { documentation::testSpecificationAndThrow( Documentation(), @@ -56,13 +60,10 @@ TorrentSynchronization::TorrentSynchronization(const ghoul::Dictionary& dict) _identifier = dict.value(KeyIdentifier); _magnetLink = dict.value(KeyMagnet); +} - // Configure synchronization based on global settings in SyncModule - // TODO: For testability and decreaing deps, make it possible to inject this instead. - // For example, allow this configuration to be done by the TemplateFactory. - SyncModule* syncModule = OsEng.moduleEngine().module(); - _synchronizationRoot = syncModule->synchronizationRoot(); - _torrentClient = syncModule->torrentClient(); +TorrentSynchronization::~TorrentSynchronization() { + cancel(); } documentation::Documentation TorrentSynchronization::Documentation() { @@ -160,18 +161,22 @@ void TorrentSynchronization::createSyncFile() { } size_t TorrentSynchronization::nSynchronizedBytes() { + std::lock_guard g(_progressMutex); return _progress.nDownloadedBytes; } size_t TorrentSynchronization::nTotalBytes() { + std::lock_guard g(_progressMutex); return _progress.nTotalBytes; } bool TorrentSynchronization::nTotalBytesIsKnown() { + std::lock_guard g(_progressMutex); return _progress.nTotalBytesKnown; } void TorrentSynchronization::updateTorrentProgress(TorrentClient::TorrentProgress progress) { + std::lock_guard g(_progressMutex); _progress = progress; if (progress.finished && state() == State::Syncing) { createSyncFile(); diff --git a/modules/sync/syncs/torrentsynchronization.h b/modules/sync/syncs/torrentsynchronization.h index 4865b47bb5..889bc8becd 100644 --- a/modules/sync/syncs/torrentsynchronization.h +++ b/modules/sync/syncs/torrentsynchronization.h @@ -43,7 +43,12 @@ class TorrentSynchronizationJob; class TorrentSynchronization : public ResourceSynchronization { public: - TorrentSynchronization(const ghoul::Dictionary& dict); + TorrentSynchronization(const ghoul::Dictionary& dict, + const std::string& synchronizationRoot, + TorrentClient* client); + + + virtual ~TorrentSynchronization(); static documentation::Documentation Documentation(); std::string directory() override; @@ -64,6 +69,7 @@ private: std::atomic_bool _enabled = false; size_t _torrentId; TorrentClient::TorrentProgress _progress; + std::mutex _progressMutex; std::string _identifier; std::string _magnetLink; std::string _synchronizationRoot; diff --git a/modules/sync/torrentclient.cpp b/modules/sync/torrentclient.cpp index 812f2317d1..396c1fdc8d 100644 --- a/modules/sync/torrentclient.cpp +++ b/modules/sync/torrentclient.cpp @@ -91,7 +91,7 @@ void TorrentClient::pollAlerts() { std::lock_guard guard(_mutex); _session->pop_alerts(&alerts); } - + for (lt::alert const* a : alerts) { //LINFO(a->message()); // if we receive the finished alert or an error, we're done diff --git a/modules/touch/touchmodule.cpp b/modules/touch/touchmodule.cpp index eb7505c81f..77f33c35c2 100644 --- a/modules/touch/touchmodule.cpp +++ b/modules/touch/touchmodule.cpp @@ -112,6 +112,10 @@ TouchModule::TouchModule() addPropertySubOwner(touch); addPropertySubOwner(markers); + if (!OpenSpaceEngine::isCreated()) { + return; + } + OsEng.registerModuleCallback( OpenSpaceEngine::CallbackOption::InitializeGL, [&]() { diff --git a/openspace.cfg b/openspace.cfg index 3881af3844..e7bfe7bb77 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -95,8 +95,13 @@ return { -- PerSceneCache = true, -- DisableRenderingOnMaster = true, -- DisableSceneOnMaster = true, - HttpSynchronizationRepositories = { - "data.openspaceproject.com/request" + ModuleConfigurations = { + Sync = { + SynchronizationRoot = "${SYNC}", + HttpSynchronizationRepositories = { + "data.openspaceproject.com/request" + } + } }, RenderingMethod = "Framebuffer", OpenGLDebugContext = { diff --git a/src/engine/configurationmanager.cpp b/src/engine/configurationmanager.cpp index f253fdb33b..b74f94c568 100644 --- a/src/engine/configurationmanager.cpp +++ b/src/engine/configurationmanager.cpp @@ -86,8 +86,6 @@ const string ConfigurationManager::KeyRenderingMethod = "RenderingMethod"; const string ConfigurationManager::KeyOnScreenTextScaling = "OnScreenTextScaling"; -const string ConfigurationManager::KeyHttpSynchronizationRepositories = "HttpSynchronizationRepositories"; - const string ConfigurationManager::KeyHttpProxy = "HttpProxy"; const string ConfigurationManager::PartHttpProxyAddress = "Address"; const string ConfigurationManager::PartHttpProxyPort = "Port"; @@ -114,6 +112,8 @@ const string ConfigurationManager::PartShowMessage = "ShowMessage"; const string ConfigurationManager::PartShowNodeNames = "ShowNodeNames"; const string ConfigurationManager::PartShowProgressbar = "ShowProgressbar"; +const string ConfigurationManager::KeyModuleConfigurations = "ModuleConfigurations"; + string ConfigurationManager::findConfiguration(const string& filename) { using ghoul::filesystem::Directory; diff --git a/src/engine/configurationmanager_doc.inl b/src/engine/configurationmanager_doc.inl index bda26c00c2..ecead94309 100644 --- a/src/engine/configurationmanager_doc.inl +++ b/src/engine/configurationmanager_doc.inl @@ -284,13 +284,6 @@ documentation::Documentation ConfigurationManager::Documentation() { "interaction and it is thus desired to disable the transformation. The " "default is false." }, - { - ConfigurationManager::KeyHttpSynchronizationRepositories, - new StringListVerifier("URLs to http synchronization repositories"), - Optional::Yes, - "Configures the list of http synchronization repositories to load " - "resources from. The first URL will be tried first." - }, { ConfigurationManager::KeyHttpProxy, new TableVerifier({ @@ -462,6 +455,12 @@ documentation::Documentation ConfigurationManager::Documentation() { Optional::Yes, "Values in this table describe the behavior of the loading screen that is " "displayed while the scene graph is created and initialized." + }, + { + ConfigurationManager::KeyModuleConfigurations, + new TableVerifier, + Optional::Yes, + "Configurations for each module" } } }; diff --git a/src/engine/moduleengine.cpp b/src/engine/moduleengine.cpp index e73c58ea10..3e2c26aa8e 100644 --- a/src/engine/moduleengine.cpp +++ b/src/engine/moduleengine.cpp @@ -29,6 +29,7 @@ #include #include +#include #include @@ -40,9 +41,14 @@ namespace { namespace openspace { -void ModuleEngine::initialize() { +void ModuleEngine::initialize(const ghoul::Dictionary& moduleConfigurations) { for (OpenSpaceModule* m : AllModules()) { - registerModule(std::unique_ptr(m)); + const std::string name = m->name(); + ghoul::Dictionary configuration; + if (moduleConfigurations.hasKey(name)) { + moduleConfigurations.getValue(name, configuration); + } + registerModule(std::unique_ptr(m), configuration); } } @@ -56,7 +62,9 @@ void ModuleEngine::deinitialize() { LDEBUG("Finished destroying modules"); } -void ModuleEngine::registerModule(std::unique_ptr m) { +void ModuleEngine::registerModule(std::unique_ptr m, + const ghoul::Dictionary& configuration) +{ ghoul_assert(m, "Module must not be nullptr"); auto it = std::find_if( @@ -74,7 +82,7 @@ void ModuleEngine::registerModule(std::unique_ptr m) { } LDEBUG("Registering module '" << m->name() << "'"); - m->initialize(); + m->initialize(this, configuration); LDEBUG("Registered module '" << m->name() << "'"); _modules.push_back(std::move(m)); } diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index 00bbfc771c..a7babb4b51 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -375,8 +375,18 @@ void OpenSpaceEngine::create(int argc, char** argv, " (" << OPENSPACE_VERSION_STRING << ")" ); + ghoul::Dictionary moduleConfigurations; + if (_engine->configurationManager().hasKeyAndValue( + ConfigurationManager::KeyModuleConfigurations)) + { + _engine->configurationManager().getValue( + ConfigurationManager::KeyModuleConfigurations, + moduleConfigurations + ); + } + // Register modules - _engine->_moduleEngine->initialize(); + _engine->_moduleEngine->initialize(moduleConfigurations); // After registering the modules, the documentations for the available classes // can be added as well diff --git a/src/scene/asset.cpp b/src/scene/asset.cpp index bba05fc657..0f725ff275 100644 --- a/src/scene/asset.cpp +++ b/src/scene/asset.cpp @@ -32,6 +32,31 @@ namespace { const char* _loggerCat = "Asset"; + + float syncProgress(std::vector> assets) { + size_t nTotalBytes = 0; + size_t nSyncedBytes = 0; + + for (const auto& a : assets) { + const std::vector> syncs = + a->ownSynchronizations(); + + for (const auto& sync : syncs) { + if (sync->nTotalBytesIsKnown()) { + nTotalBytes += sync->nTotalBytes(); + nSyncedBytes += sync->nSynchronizedBytes(); + } else if (sync->isSyncing()) { + // A resource is still synchronizing but its size is unknown. + // Impossible to know the global progress. + return 0; + } + } + } + if (nTotalBytes == 0) { + return 0.f; + } + return static_cast(nSyncedBytes) / static_cast(nTotalBytes); + } } namespace openspace { @@ -96,6 +121,9 @@ void Asset::setState(Asset::State state) { } void Asset::requiredAssetChangedState(std::shared_ptr child) { + ghoul_assert(!isInitialized(), + "Required asset changing state while parent asset is initialized"); + State childState = child->state(); if (childState == State::SyncResolved) { if (isSyncResolveReady()) { @@ -135,6 +163,9 @@ void Asset::addSynchronization(std::shared_ptr synchron void Asset::syncStateChanged(std::shared_ptr synchronization, ResourceSynchronization::State state) { + ghoul_assert(!isInitialized(), + "Synchronization changing state while asset is initialized"); + if (state == ResourceSynchronization::State::Resolved) { if (!isSynchronized() && isSyncResolveReady()) { setState(State::SyncResolved); @@ -317,7 +348,7 @@ bool Asset::startSynchronizations() { foundUnresolved = true; } } - for (auto& child : requiredAssets()) { + for (auto& child : requestedAssets()) { child->startSynchronizations(); } @@ -385,29 +416,15 @@ bool Asset::restartAllSynchronizations() { return startSynchronizations(); } -float Asset::synchronizationProgress() { +float Asset::requiredSynchronizationProgress() { std::vector> assets = requiredSubTreeAssets(); + return syncProgress(assets); - size_t nTotalBytes = 0; - size_t nSyncedBytes = 0; +} - for (const auto& a : assets) { - const std::vector> syncs = - a->ownSynchronizations(); - - for (const auto& sync : syncs) { - if (sync->nTotalBytesIsKnown()) { - nTotalBytes += sync->nTotalBytes(); - nSyncedBytes += sync->nSynchronizedBytes(); - } else { - return 0; - } - } - } - if (nTotalBytes == 0) { - return 1.f; - } - return static_cast(nSyncedBytes) / static_cast(nTotalBytes); +float Asset::requestedSynchronizationProgress() { + std::vector> assets = subTreeAssets(); + return syncProgress(assets); } void Asset::load() { @@ -706,13 +723,23 @@ void Asset::request(std::shared_ptr child) { if (!child->isLoaded()) { child->load(); } - - if (isSynchronized() && child->isLoaded() && !child->isSynchronized()) { - child->startSynchronizations(); + if (!child->isLoaded()) { + unrequest(child); } - if (isInitialized() && child->isSynchronized() && !child->isInitialized()) { - child->initialize(); + if (isSynchronized()) { + if (child->isLoaded() && !child->isSynchronized()) { + child->startSynchronizations(); + } + } + + if (isInitialized()) { + if (child->isSynchronized() && !child->isInitialized()) { + child->initialize(); + } + if (!child->isInitialized()) { + unrequest(child); + } } } @@ -733,8 +760,8 @@ void Asset::unrequest(std::shared_ptr child) { child->_requestingAssets.begin(), child->_requestingAssets.end(), [this](std::weak_ptr a) { - return a.lock().get() == this; - } + return a.lock().get() == this; + } ); if (parentIt == child->_requestingAssets.end()) { diff --git a/src/util/httprequest.cpp b/src/util/httprequest.cpp index ab01db2bfb..41bf672e71 100644 --- a/src/util/httprequest.cpp +++ b/src/util/httprequest.cpp @@ -291,8 +291,12 @@ bool HttpFileDownload::initDownload() { ghoul::filesystem::File destinationFile = _destination; ghoul::filesystem::Directory d = destinationFile.directoryName(); - if (!FileSys.directoryExists(d)) { - FileSys.createDirectory(d, ghoul::filesystem::Directory::Recursive::Yes); + + { + std::lock_guard g(_directoryCreationMutex); + if (!FileSys.directoryExists(d)) { + FileSys.createDirectory(d, ghoul::filesystem::Directory::Recursive::Yes); + } } _file = std::ofstream(_destination, std::ofstream::binary); @@ -314,6 +318,8 @@ size_t HttpFileDownload::handleData(HttpRequest::Data d) { return d.size; } +std::mutex HttpFileDownload::_directoryCreationMutex; + SyncHttpMemoryDownload::SyncHttpMemoryDownload(std::string url) : SyncHttpDownload(std::move(url)) , HttpMemoryDownload() diff --git a/src/util/openspacemodule.cpp b/src/util/openspacemodule.cpp index 2a5b036666..0dac849ac7 100644 --- a/src/util/openspacemodule.cpp +++ b/src/util/openspacemodule.cpp @@ -28,6 +28,7 @@ #include #include +#include #include @@ -44,7 +45,9 @@ OpenSpaceModule::OpenSpaceModule(std::string name) : properties::PropertyOwner({ std::move(name) }) {} -void OpenSpaceModule::initialize() { +void OpenSpaceModule::initialize(const ModuleEngine* moduleEngine, + const ghoul::Dictionary& configuration) +{ std::string upperName = name(); std::transform( upperName.begin(), @@ -63,7 +66,8 @@ void OpenSpaceModule::initialize() { LDEBUG("Registering module path: " << moduleToken << ": " << path); FileSys.registerPathToken(moduleToken, path); - internalInitialize(); + _moduleEngine = moduleEngine; + internalInitialize(configuration); } void OpenSpaceModule::deinitialize() { @@ -111,7 +115,17 @@ std::string OpenSpaceModule::modulePath() const { ); } +const ModuleEngine* OpenSpaceModule::moduleEngine() const +{ + return _moduleEngine; +} + void OpenSpaceModule::internalInitialize() {} + +void OpenSpaceModule::internalInitialize(const ghoul::Dictionary&) { + internalInitialize(); +} + void OpenSpaceModule::internalDeinitialize() {} } // namespace openspace diff --git a/tests/test_assetloader.inl b/tests/test_assetloader.inl index 25351cd30d..a79b0afbea 100644 --- a/tests/test_assetloader.inl +++ b/tests/test_assetloader.inl @@ -39,7 +39,6 @@ #include - #include #include @@ -79,7 +78,6 @@ protected: } openspace::Scene _scene; - std::unique_ptr _resourceSynchronizer; std::unique_ptr _assetLoader; bool _passedTest; }; @@ -96,17 +94,17 @@ int passTest(lua_State* state) { TEST_F(AssetLoaderTest, Assertions) { try { - _assetLoader->loadAsset("passassertion"); + _assetLoader->add("passassertion"); } catch (const std::exception& e) { EXPECT_TRUE(false) << e.what(); } - EXPECT_THROW(_assetLoader->loadAsset("failassertion"), ghoul::lua::LuaRuntimeException); + EXPECT_THROW(_assetLoader->add("failassertion"), ghoul::lua::LuaRuntimeException); } TEST_F(AssetLoaderTest, BasicExportImport) { try { - _assetLoader->loadAsset("import"); + _assetLoader->add("import"); } catch (const std::exception& e) { EXPECT_TRUE(false) << e.what(); @@ -115,7 +113,7 @@ TEST_F(AssetLoaderTest, BasicExportImport) { TEST_F(AssetLoaderTest, AssetFuncitons) { try { - _assetLoader->loadAsset("assetfunctionsexist"); + _assetLoader->add("assetfunctionsexist"); } catch (const std::exception& e) { EXPECT_TRUE(false) << e.what(); } @@ -123,7 +121,7 @@ TEST_F(AssetLoaderTest, AssetFuncitons) { TEST_F(AssetLoaderTest, DependencyFuncitons) { try { - _assetLoader->loadAsset("dependencyfunctionsexist"); + _assetLoader->add("dependencyfunctionsexist"); } catch (const std::exception& e) { EXPECT_TRUE(false) << e.what(); @@ -132,7 +130,7 @@ TEST_F(AssetLoaderTest, DependencyFuncitons) { TEST_F(AssetLoaderTest, AssetInitialization) { try { - std::shared_ptr asset = _assetLoader->loadAsset("initialization"); + std::shared_ptr asset = _assetLoader->add("initialization"); asset->initialize(); EXPECT_TRUE(passed()); }