mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-03-10 23:38:38 -05:00
@@ -92,7 +92,6 @@ public:
|
||||
std::vector<std::byte> encode();
|
||||
void decode(std::vector<std::byte> data);
|
||||
|
||||
void scheduleLoadSingleAsset(std::string assetPath);
|
||||
void toggleShutdownMode();
|
||||
|
||||
// Guaranteed to return a valid pointer
|
||||
@@ -110,7 +109,7 @@ public:
|
||||
static scripting::LuaLibrary luaLibrary();
|
||||
|
||||
private:
|
||||
void loadAsset(const std::string& assetName);
|
||||
void loadAssets();
|
||||
void loadFonts();
|
||||
|
||||
void runGlobalCustomizationScripts();
|
||||
@@ -126,9 +125,6 @@ private:
|
||||
std::unique_ptr<LoadingScreen> _loadingScreen;
|
||||
std::unique_ptr<VersionChecker> _versionChecker;
|
||||
|
||||
bool _hasScheduledAssetLoading = false;
|
||||
std::string _scheduledAssetPathToLoad;
|
||||
|
||||
glm::vec2 _mousePosition = glm::vec2(0.f);
|
||||
|
||||
//grabs json from each module to pass to the documentation engine.
|
||||
|
||||
@@ -26,156 +26,276 @@
|
||||
#define __OPENSPACE_CORE___ASSET___H__
|
||||
|
||||
#include <openspace/util/resourcesynchronization.h>
|
||||
#include <openspace/util/synchronizationwatcher.h>
|
||||
#include <memory>
|
||||
#include <filesystem>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace openspace {
|
||||
|
||||
class AssetLoader;
|
||||
class AssetManager;
|
||||
|
||||
class Asset : public std::enable_shared_from_this<Asset> {
|
||||
/**
|
||||
* This class represents a successfully loaded Asset. Each Lua asset file results in
|
||||
* exactly one instance of this class unless it contains a syntax error or some other
|
||||
* error occurred while loading. Each Asset can have 0-* number of resource
|
||||
* synchronizations that were requested through the `syncedResource` function in Lua and
|
||||
* 0-* number of other Assets that this Asset requires (through the `require` function in
|
||||
* Lua. There also is a list of requiring assets that contain all assets which require
|
||||
* this asset.
|
||||
* An asset goes through three external states. Starting out as unloaded when the instance
|
||||
* is newly created but the file has not been processed. In this case the #isLoaded,
|
||||
* #isSynchronized and the #isInitialized functions all return \c false. After the asset
|
||||
* has been loaded it is in the \c Loaded state (#isLoaded = true,
|
||||
* #isSynchronized = false, #isInitialized = false). After all registered synchronizations
|
||||
* finish successfully, the Asset transitions into the Synchronized state
|
||||
* (#isLoaded = true, #isSynchronized = true, #isInitialized = false) and after the final
|
||||
* initialization step, the asset is initialized (#isLoaded = true,
|
||||
* #isSynchronized = true and #isInitialized = true)
|
||||
*/
|
||||
class Asset {
|
||||
public:
|
||||
enum class State {
|
||||
Unloaded,
|
||||
LoadingFailed,
|
||||
Loaded,
|
||||
Synchronizing,
|
||||
SyncResolved,
|
||||
SyncRejected,
|
||||
Initialized,
|
||||
InitializationFailed
|
||||
};
|
||||
|
||||
/// This struct contains all the meta information about this asset
|
||||
struct MetaInformation {
|
||||
/// The name of the asset
|
||||
std::string name;
|
||||
/// The version number of the asset. This is only a string representation and does
|
||||
/// not have to follow SemVer (even though it is advised)
|
||||
std::string version;
|
||||
/// A user-facing description of the asset contents
|
||||
std::string description;
|
||||
/// The author of the asset
|
||||
std::string author;
|
||||
/// A URL where a consumer of the asset might find additional information about,
|
||||
/// for example, the author or the used dataset(s)
|
||||
std::string url;
|
||||
/// The license under which this asset has been provided
|
||||
std::string license;
|
||||
/// A list of all scene graph nodes that have been created in this asset
|
||||
std::vector<std::string> identifiers;
|
||||
};
|
||||
|
||||
/**
|
||||
* Root asset constructor
|
||||
* Creates a new Asset that is backed by the provided \p assetPath. The \p manager is
|
||||
* the AssetManager instance that is responsible for loading this and all the other
|
||||
* required Assets.
|
||||
*
|
||||
* \param manager The AssetManager that is responsible for loading this Asset and all
|
||||
* of its dependencies
|
||||
* \param assetPath The file path that will be used to load this Asset
|
||||
*
|
||||
* \pre The \p assetPath must not be empty and must be an existing file
|
||||
*/
|
||||
Asset(AssetLoader* loader, SynchronizationWatcher* watcher);
|
||||
Asset(AssetManager& manager, std::filesystem::path assetPath);
|
||||
|
||||
/**
|
||||
* Regular asset constructor
|
||||
* Returns the path to the file that was used to initialize this Asset.
|
||||
*
|
||||
* \return The path to the file that was used to initialize this Asset
|
||||
*/
|
||||
Asset(AssetLoader* loader, SynchronizationWatcher* watcher, std::string assetPath);
|
||||
|
||||
std::string id() const;
|
||||
const std::string& assetFilePath() const;
|
||||
bool hasAssetFile() const;
|
||||
std::string assetDirectory() const;
|
||||
const std::string& assetName() const;
|
||||
AssetLoader* loader() const;
|
||||
State state() const;
|
||||
|
||||
void addSynchronization(std::unique_ptr<ResourceSynchronization> synchronization);
|
||||
void clearSynchronizations();
|
||||
std::vector<ResourceSynchronization*> ownSynchronizations() const;
|
||||
|
||||
void syncStateChanged(ResourceSynchronization* sync,
|
||||
ResourceSynchronization::State state);
|
||||
std::filesystem::path path() const;
|
||||
|
||||
/**
|
||||
* Load this asset and return true if successful,
|
||||
* i.e. if this and all required assets loaded without errors.
|
||||
* Adds a new dependent ResourceSynchronization object to this Asset.
|
||||
*
|
||||
* \param synchronization The resource synchronization object that is bound to this
|
||||
* Asset
|
||||
* \pre \p synchronization must not be nullptr
|
||||
* \pre \p synchronization must not have been added to this Asset before
|
||||
*/
|
||||
void addSynchronization(ResourceSynchronization* synchronization);
|
||||
|
||||
/**
|
||||
* Updates the state of this Asset based on the latest synchronization being
|
||||
* successfully resolved. Depending on the sum state of all registered
|
||||
* synchronizations this Asset's state changes to successfully Synchronized, or Failed
|
||||
*/
|
||||
void setSynchronizationStateResolved();
|
||||
|
||||
/**
|
||||
* Updates the state of this Asset based on the latest synchronization being rejected.
|
||||
* Depending on the sum state of all registered synchronizations this Asset's state
|
||||
* changes to successfully Synchronized, or Failed
|
||||
*/
|
||||
void setSynchronizationStateRejected();
|
||||
|
||||
/**
|
||||
* If the asset has not yet been loaded, this function loads the asset and returns the
|
||||
* success state. If the loading succeeded, the Asset transitions into the \c Loaded
|
||||
* state. The \p parent that is provided is the Asset that caused this load operation
|
||||
* to be triggered and might be \c nullptr if this asset does not have any parents. If
|
||||
* this Asset has been previously loaded (even with a different \p parent), this
|
||||
* function does nothing.
|
||||
*
|
||||
* \param parent The parent asset (or \c nullptr) that triggered this loading
|
||||
*/
|
||||
void load(Asset* parent);
|
||||
|
||||
/**
|
||||
* Returns \c true if this Asset has at least one parent that is in the Loaded state.
|
||||
*
|
||||
* \return \c true if this Asset has at least one parent that is in the Loaded state
|
||||
*/
|
||||
bool load();
|
||||
bool hasLoadedParent();
|
||||
|
||||
/**
|
||||
* Returns \c true if this Asset has been successfully #load ed.
|
||||
*
|
||||
* /return \c true if this Asset has been successfully loaded
|
||||
*/
|
||||
bool isLoaded() const;
|
||||
|
||||
/**
|
||||
* Unloads this Asset and unrequires all of its required assets, potentially causing
|
||||
* a cascading effect of further #unload calls if this asset was those required assets
|
||||
* only parent. After this call, this Asset will be in the Unloaded state. If this
|
||||
* Asset has already been unloaded (or has not yet been loaded), this function does
|
||||
* nothing.
|
||||
*/
|
||||
void unload();
|
||||
void unloadIfUnwanted();
|
||||
|
||||
/**
|
||||
* Start synchronizations of this asset and return true if all
|
||||
* its own synchronizations and required assets' synchronizations could start.
|
||||
* Starts the registered synchronizations of this asset and returns \c true if all its
|
||||
* synchronizations and required assets' synchronizations could start. When all
|
||||
* synchronizations have completed successfully, this Asset transitions into the
|
||||
* Synchronized state.
|
||||
*
|
||||
* \pre This Asset must have been Loaded before
|
||||
*/
|
||||
bool startSynchronizations();
|
||||
float requiredSynchronizationProgress() const;
|
||||
float requestedSynchronizationProgress();
|
||||
void startSynchronizations();
|
||||
|
||||
/**
|
||||
* Initialize this asset and return true if successful,
|
||||
* i.e. if this and all required assets initialized without errors.
|
||||
* Returns \c true if this Asset's synchronizations (if any) have completed
|
||||
* successfully.
|
||||
*
|
||||
* \return \c true if this Asset is in the Synchronized or Initialized state
|
||||
*/
|
||||
bool isSynchronized() const;
|
||||
|
||||
/**
|
||||
* Initializes this asset and returns \c true if the initialized succeeded, i.e. if
|
||||
* this and all required assets initialized without errors. After this call, if it has
|
||||
* been successful, this Asset is in the Initialized state. If the Asset has already
|
||||
* been initialized, calling this function does nothing.
|
||||
*/
|
||||
void initialize();
|
||||
|
||||
/**
|
||||
* Returns \c true if this Asset has been #initialize d successfully.
|
||||
*
|
||||
* \return \c true if this Asset has been #initialize d successfully. It returns
|
||||
* \c false both if this initialization failed as well as if thie #initialize
|
||||
* function has not been called on this Asset
|
||||
*/
|
||||
bool initialize();
|
||||
bool hasInitializedParent() const;
|
||||
bool isInitialized() const;
|
||||
|
||||
/**
|
||||
* Returns whether any of the parents of this Asset is currently in an initialized
|
||||
* state, meaning that any parent is still interested in this Asset at all.
|
||||
*
|
||||
* \return \c true if there is at least one initialized parent, \c false otherwise
|
||||
*/
|
||||
bool hasInitializedParent() const;
|
||||
|
||||
/**
|
||||
* Deinitializes this Asset and recursively deinitializes the required assets if this
|
||||
* Asset was their ownly initialized parent. If the Asset was already deinitialized,
|
||||
* calling this function does nothing.
|
||||
*/
|
||||
void deinitialize();
|
||||
void deinitializeIfUnwanted();
|
||||
|
||||
// Dependency graph
|
||||
bool requires(const Asset* asset) const;
|
||||
void require(std::shared_ptr<Asset> child);
|
||||
void unrequire(Asset* child);
|
||||
/**
|
||||
* Marks the passed \p child as being required by \p this Asset. If the \p child is
|
||||
* already required by this asset, this function does nothing.
|
||||
*
|
||||
* \param child The asset that is required by this asset
|
||||
* \pre \p child must not be nullptr
|
||||
*/
|
||||
void require(Asset* child);
|
||||
|
||||
bool requests(Asset* asset) const;
|
||||
void request(std::shared_ptr<Asset> child);
|
||||
void unrequest(Asset* child);
|
||||
|
||||
std::vector<Asset*> requestedAssets() const;
|
||||
std::vector<Asset*> requestingAssets() const;
|
||||
std::vector<Asset*> requiredAssets() const;
|
||||
std::vector<Asset*> requiringAssets() const;
|
||||
|
||||
std::vector<const Asset*> subTreeAssets() const;
|
||||
std::vector<Asset*> childAssets() const;
|
||||
/**
|
||||
* Returns \c true if the loading of the Asset has failed in any way so that
|
||||
* recovering from the error is impossible.
|
||||
*
|
||||
* \return \c true if the Asset handling failed in any way, \c false otherwise
|
||||
*/
|
||||
bool isFailed() const;
|
||||
|
||||
/**
|
||||
* Sets the provided \p metaInformation as the meta information struct for this asset.
|
||||
* If previous information existed, it will be silently overwritten.
|
||||
*
|
||||
* \param metaInformation The meta information about this asset
|
||||
*/
|
||||
void setMetaInformation(MetaInformation metaInformation);
|
||||
|
||||
/**
|
||||
* Returns the meta information of this asset back to the caller. If no such
|
||||
* information exists, a \c std::nullopt will be returned.
|
||||
*
|
||||
* \return The MetaInformation about this asset or \c std::nullopt
|
||||
*/
|
||||
std::optional<MetaInformation> metaInformation() const;
|
||||
|
||||
private:
|
||||
/// All of the (internal) states that the Asset can move through. The externally
|
||||
/// visible states (Loaded, Synchronized, Initialized) are a subset of these states
|
||||
enum class State {
|
||||
/// The asset is created, but the Lua file has not been executed yet
|
||||
Unloaded,
|
||||
/// The execution of the asset file as Lua failed with some error
|
||||
LoadingFailed,
|
||||
/// The loading of the asset file succeeded
|
||||
Loaded,
|
||||
/// The Asset is currently synchronizing its ResourceSynchronizations and waiting
|
||||
/// for them to finish
|
||||
Synchronizing,
|
||||
/// All registered synchronizations have completed successfully
|
||||
Synchronized,
|
||||
/// At least one of the registered synchronizations failed to synchronize
|
||||
SyncRejected,
|
||||
/// The onInitialize method (if the asset has one) was executed successfully
|
||||
Initialized,
|
||||
/// The execution of the onInitialize method (if existing) resulted in a Lua error
|
||||
InitializationFailed
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the \p state of this Asset to the new state. Depending on the current state of
|
||||
* this Asset, if \p state is a state related to the synchronization, it will
|
||||
* potentially propagate to this Asset's parents and cause them to be set to be
|
||||
* successfully synchronized or faild.
|
||||
*
|
||||
* \param state The new State that this Asset is set to
|
||||
*/
|
||||
void setState(State state);
|
||||
|
||||
void requiredAssetChangedState(Asset::State childState);
|
||||
void requestedAssetChangedState(Asset* child, Asset::State childState);
|
||||
|
||||
bool isSynchronized() const;
|
||||
/// Returns whether the Asset is synchronizing or has successfully synchronized
|
||||
bool isSyncingOrResolved() const;
|
||||
bool isSyncResolveReady();
|
||||
bool hasSyncingOrResolvedParent() const;
|
||||
bool cancelAllSynchronizations();
|
||||
bool cancelUnwantedSynchronizations();
|
||||
|
||||
std::vector<const Asset*> requiredSubTreeAssets() const;
|
||||
/// Returns whether the Asset has been successfully synchronized, meaning that both
|
||||
/// its own resource synchronizations are finished as well as all requiered assets are
|
||||
/// finished synchronizing
|
||||
bool isSyncResolveReady() const;
|
||||
|
||||
std::atomic<State> _state;
|
||||
AssetLoader* _loader;
|
||||
SynchronizationWatcher* _synchronizationWatcher;
|
||||
/// The state that this Asset is currently in
|
||||
std::atomic<State> _state = State::Unloaded;
|
||||
|
||||
std::vector<std::shared_ptr<ResourceSynchronization>> _synchronizations;
|
||||
/// Reference to the manager that is responsible for loading and unloading this asset
|
||||
AssetManager& _manager;
|
||||
|
||||
bool _hasAssetPath;
|
||||
// The name of the asset
|
||||
std::string _assetName;
|
||||
|
||||
// Absolute path to asset file
|
||||
std::string _assetPath;
|
||||
/// Absolute path to asset file
|
||||
std::filesystem::path _assetPath;
|
||||
|
||||
/// Additional information about this asset, such as its name, author, license, etc
|
||||
std::optional<MetaInformation> _metaInformation;
|
||||
|
||||
// Required assets
|
||||
std::vector<std::shared_ptr<Asset>> _requiredAssets;
|
||||
/// Assets that are required by this asset
|
||||
std::vector<Asset*> _requiredAssets;
|
||||
|
||||
// Assets that refers to this asset as a required asset
|
||||
std::vector<std::weak_ptr<Asset>> _requiringAssets;
|
||||
/// Assets that refers to this asset as a required asset
|
||||
std::vector<Asset*> _parentAssets;
|
||||
|
||||
// Requested assets
|
||||
std::vector<std::shared_ptr<Asset>> _requestedAssets;
|
||||
|
||||
// Assets that refers to this asset as a requested asset
|
||||
std::vector<std::weak_ptr<Asset>> _requestingAssets;
|
||||
|
||||
// Synchronization watches
|
||||
std::vector<SynchronizationWatcher::WatchHandle> _syncWatches;
|
||||
/// Synchronizations that were requested by this asset
|
||||
std::vector<ResourceSynchronization*> _synchronizations;
|
||||
};
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2021 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_CORE___ASSETLISTENER___H__
|
||||
#define __OPENSPACE_CORE___ASSETLISTENER___H__
|
||||
|
||||
#include <openspace/scene/asset.h>
|
||||
|
||||
namespace openspace {
|
||||
|
||||
class AssetListener {
|
||||
public:
|
||||
virtual ~AssetListener() = default;
|
||||
virtual void assetStateChanged(Asset* asset, Asset::State state) = 0;
|
||||
virtual void assetRequested(Asset* parent, std::shared_ptr<Asset> child) = 0;
|
||||
virtual void assetUnrequested(Asset* parent, std::shared_ptr<Asset> child) = 0;
|
||||
};
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __OPENSPACE_CORE___ASSETLISTENER___H__
|
||||
@@ -1,225 +0,0 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2021 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_CORE___ASSETLOADER___H__
|
||||
#define __OPENSPACE_CORE___ASSETLOADER___H__
|
||||
|
||||
#include <openspace/scene/asset.h>
|
||||
#include <filesystem>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
struct lua_State;
|
||||
|
||||
namespace ghoul::filesystem { class Directory; }
|
||||
namespace ghoul::lua { class LuaState; }
|
||||
|
||||
namespace openspace {
|
||||
|
||||
namespace assetloader {
|
||||
|
||||
int onInitialize(lua_State* state);
|
||||
int onDeinitialize(lua_State* state);
|
||||
int onInitializeDependency(lua_State* state);
|
||||
int onDeinitializeDependency(lua_State* state);
|
||||
int require(lua_State* state);
|
||||
int exists(lua_State* state);
|
||||
int localResource(lua_State* state);
|
||||
int syncedResource(lua_State* state);
|
||||
int exportAsset(lua_State* state);
|
||||
|
||||
} // namespace assetloader
|
||||
|
||||
class AssetListener;
|
||||
class ResourceSynchronization;
|
||||
class SynchronizationWatcher;
|
||||
|
||||
class AssetLoader {
|
||||
public:
|
||||
AssetLoader(ghoul::lua::LuaState* luaState, SynchronizationWatcher* syncWatcher,
|
||||
std::string assetRootDirectory);
|
||||
|
||||
~AssetLoader();
|
||||
|
||||
/**
|
||||
* Add the asset as a request of the root asset
|
||||
*/
|
||||
std::shared_ptr<Asset> add(const std::string& identifier);
|
||||
|
||||
/**
|
||||
* Remove the asset as a request of the root asset
|
||||
*/
|
||||
void remove(const std::string& identifier);
|
||||
|
||||
/**
|
||||
* Enable the asset to be reused when the same path is required/requested again
|
||||
*/
|
||||
void trackAsset(std::shared_ptr<Asset> asset);
|
||||
|
||||
/**
|
||||
* Disable the asset from being reused when the same path is required/requested again
|
||||
*/
|
||||
void untrackAsset(Asset* asset);
|
||||
|
||||
/**
|
||||
* Return the asset identified by the identifier,
|
||||
* if the asset is tracked. Otherwise return nullptr.
|
||||
*/
|
||||
std::shared_ptr<Asset> has(const std::string& identifier) const;
|
||||
|
||||
/// Return the root asset
|
||||
const Asset& rootAsset() const;
|
||||
|
||||
/// Return the root asset
|
||||
Asset& rootAsset();
|
||||
|
||||
/**
|
||||
* Return the asset root directory
|
||||
*/
|
||||
const std::string& assetRootDirectory() const;
|
||||
|
||||
/**
|
||||
* Load an asset
|
||||
*/
|
||||
bool loadAsset(Asset* asset);
|
||||
|
||||
/**
|
||||
* Unload an asset
|
||||
*/
|
||||
void unloadAsset(Asset* asset);
|
||||
|
||||
/**
|
||||
* Call the onInitialize function specified in the asset file
|
||||
*/
|
||||
void callOnInitialize(Asset* asset);
|
||||
|
||||
/**
|
||||
* Call the onDeinitialize function specified in the asset file
|
||||
*/
|
||||
void callOnDeinitialize(Asset* asset);
|
||||
|
||||
/**
|
||||
* Call the dependency.onInitialize function specified in the asset file
|
||||
*/
|
||||
void callOnDependencyInitialize(Asset* asset, Asset* dependant);
|
||||
|
||||
/**
|
||||
* Call the dependency.onDeinitialize function specified in the asset file
|
||||
*/
|
||||
void callOnDependencyDeinitialize(Asset* asset, Asset* dependant);
|
||||
|
||||
/**
|
||||
* Generate the absolute path for an asset specified as `path`
|
||||
* relative to `baseDirectory`
|
||||
*/
|
||||
std::string generateAssetPath(const std::string& baseDirectory,
|
||||
const std::string& assetPath) const;
|
||||
|
||||
/**
|
||||
* Add listener to asset state changes
|
||||
*/
|
||||
void addAssetListener(AssetListener* listener);
|
||||
|
||||
/**
|
||||
* Remove listener to asset state changes
|
||||
*/
|
||||
void removeAssetListener(AssetListener* listener);
|
||||
|
||||
/**
|
||||
* Notify listeners about asset state change
|
||||
*/
|
||||
void assetStateChanged(Asset* asset, Asset::State state);
|
||||
|
||||
/**
|
||||
* Notify listeners about new requests
|
||||
*/
|
||||
void assetRequested(Asset* parent, std::shared_ptr<Asset> child);
|
||||
|
||||
/**
|
||||
* Notify listeners about removed requests
|
||||
*/
|
||||
void assetUnrequested(Asset* parent, std::shared_ptr<Asset> child);
|
||||
|
||||
private:
|
||||
void unrequest(const std::string& identifier);
|
||||
|
||||
void setUpAssetLuaTable(Asset* asset);
|
||||
void tearDownAssetLuaTable(Asset* asset);
|
||||
|
||||
std::shared_ptr<Asset> getAsset(const std::string& name);
|
||||
std::filesystem::path currentDirectory() const;
|
||||
|
||||
void setCurrentAsset(Asset* asset);
|
||||
void addLuaDependencyTable(Asset* dependant, Asset* dependency);
|
||||
|
||||
// Lua functions
|
||||
int onInitializeLua(Asset* asset);
|
||||
int onDeinitializeLua(Asset* asset);
|
||||
int onInitializeDependencyLua(Asset* dependant, Asset* dependency);
|
||||
int onDeinitializeDependencyLua(Asset* dependant, Asset* dependency);
|
||||
int requireLua(Asset* dependant);
|
||||
int requestLua(Asset* parent);
|
||||
int existsLua(Asset* asset);
|
||||
int localResourceLua(Asset* asset);
|
||||
int syncedResourceLua(Asset* asset);
|
||||
int exportAssetLua(Asset* asset);
|
||||
|
||||
// Friend C closures (callable from Lua, and maps to Lua functions above)
|
||||
friend int assetloader::onInitialize(lua_State* state);
|
||||
friend int assetloader::onDeinitialize(lua_State* state);
|
||||
friend int assetloader::onInitializeDependency(lua_State* state);
|
||||
friend int assetloader::onDeinitializeDependency(lua_State* state);
|
||||
friend int assetloader::require(lua_State* state);
|
||||
friend int assetloader::exists(lua_State* state);
|
||||
friend int assetloader::localResource(lua_State* state);
|
||||
friend int assetloader::syncedResource(lua_State* state);
|
||||
friend int assetloader::exportAsset(lua_State* state);
|
||||
|
||||
// Member variables
|
||||
std::shared_ptr<Asset> _rootAsset;
|
||||
Asset* _currentAsset = nullptr;
|
||||
std::unordered_map<std::string, std::weak_ptr<Asset>> _trackedAssets;
|
||||
SynchronizationWatcher* _synchronizationWatcher;
|
||||
std::string _assetRootDirectory;
|
||||
ghoul::lua::LuaState* _luaState;
|
||||
|
||||
// State change listeners
|
||||
std::vector<AssetListener*> _assetListeners;
|
||||
|
||||
// References to Lua values
|
||||
std::unordered_map<Asset*, std::vector<int>> _onInitializationFunctionRefs;
|
||||
std::unordered_map<Asset*, std::vector<int>> _onDeinitializationFunctionRefs;
|
||||
std::unordered_map<Asset*, std::map<Asset*, std::vector<int>>>
|
||||
_onDependencyInitializationFunctionRefs;
|
||||
std::unordered_map<Asset*, std::map<Asset*, std::vector<int>>>
|
||||
_onDependencyDeinitializationFunctionRefs;
|
||||
|
||||
int _assetsTableRef = 0;
|
||||
};
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __OPENSPACE_CORE___ASSETLOADER___H__
|
||||
@@ -25,58 +25,184 @@
|
||||
#ifndef __OPENSPACE_CORE___ASSETMANAGER___H__
|
||||
#define __OPENSPACE_CORE___ASSETMANAGER___H__
|
||||
|
||||
#include <openspace/scene/assetlistener.h>
|
||||
|
||||
#include <openspace/scene/assetloader.h>
|
||||
#include <ghoul/lua/ghoul_lua.h>
|
||||
#include <ghoul/lua/luastate.h>
|
||||
#include <memory>
|
||||
#include <filesystem>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace openspace {
|
||||
|
||||
namespace scripting { struct LuaLibrary; }
|
||||
|
||||
class Asset;
|
||||
class AssetLoader;
|
||||
class SynchronizationWatcher;
|
||||
class ResourceSynchronization;
|
||||
|
||||
/**
|
||||
* Interface for managing assets.
|
||||
* The asset manager interface is only concerned with "top level" assets, and not their
|
||||
* dependencies. However, an asset is not considered synchronized before all its deps are
|
||||
* synchronized. Also, setting a target state of an asset to Unloaded will only unload an
|
||||
* asset from the system if it is not a dependency of a loaded asset.
|
||||
* The AssetManager class manages the loading, initialization, and unloading of all assets
|
||||
* loaded in OpenSpace. Most actions of this class are operating in a two-step process
|
||||
* where first the intent of an action is registered, which is then executed in the next
|
||||
* call to the #update function.
|
||||
* All assets are loading through the same Lua state.
|
||||
*/
|
||||
class AssetManager : AssetListener {
|
||||
class AssetManager {
|
||||
public:
|
||||
AssetManager(ghoul::lua::LuaState* state, std::string assetRootDirectory);
|
||||
AssetManager(ghoul::lua::LuaState* state, std::filesystem::path assetRootDirectory);
|
||||
~AssetManager();
|
||||
|
||||
virtual ~AssetManager() = default;
|
||||
|
||||
void initialize();
|
||||
void deinitialize();
|
||||
|
||||
/**
|
||||
* Loads the asset at the provided \p path as a new root asset of the AssetManager.
|
||||
* If the asset at that path was already loaded, nothing happens.
|
||||
*
|
||||
* \param path The path from which the Asset is loaded. This path can be either
|
||||
* relative to the base directory (the path starting with . or ..), an absolute
|
||||
* path (that path starting with *:/ or /) or relative to the global asset root
|
||||
* (if the path starts any other way)
|
||||
* \pre \p path must not be the empty string
|
||||
*/
|
||||
void add(const std::string& path);
|
||||
|
||||
/**
|
||||
* Removes the asset at the provided \p path if it has been loaded by this
|
||||
* AssetManager. If the asset at that path was not found, nothing happens.
|
||||
*
|
||||
* \param path The path from which the Asset is loaded. This path can be either
|
||||
* relative to the base directory (the path starting with . or ..), an absolute
|
||||
* path (that path starting with *:/ or /) or relative to the global asset root
|
||||
* (if the path starts any other way)
|
||||
* \pre \p path must not be the empty string
|
||||
*/
|
||||
void remove(const std::string& path);
|
||||
void removeAll();
|
||||
const Asset& rootAsset() const;
|
||||
Asset& rootAsset();
|
||||
|
||||
void assetStateChanged(Asset* asset, Asset::State state) override;
|
||||
void assetRequested(Asset* parent, std::shared_ptr<Asset> child) override;
|
||||
void assetUnrequested(Asset* parent, std::shared_ptr<Asset> child) override;
|
||||
/**
|
||||
* Update function that should be called at least once per frame that will load all
|
||||
* queued asset loads and asset removal.
|
||||
*/
|
||||
void update();
|
||||
|
||||
bool update();
|
||||
scripting::LuaLibrary luaLibrary();
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, bool> _pendingStateChangeCommands;
|
||||
std::mutex _pendingInitializationsMutex;
|
||||
std::vector<std::shared_ptr<Asset>> _pendingInitializations;
|
||||
/**
|
||||
* Returns all assets that have been loaded by the AssetManager. The order of the
|
||||
* assets is undefined.
|
||||
*
|
||||
* \return A list of all assets that have been previously loaded by the AssetManager
|
||||
*/
|
||||
std::vector<const Asset*> allAssets() const;
|
||||
|
||||
SynchronizationWatcher _synchronizationWatcher;
|
||||
AssetLoader _assetLoader;
|
||||
std::vector<const ResourceSynchronization*> allSynchronizations() const;
|
||||
|
||||
/**
|
||||
* Loads the provided \p asset as a child of the provided \p parent. Loading an asset
|
||||
* means that asset file gets executed and the meta information is extracted from it.
|
||||
* The \p parent is the asset file that caused this loading to happen and can be a
|
||||
* \c nullptr if the asset is to be loaded as a root asset.
|
||||
*
|
||||
* \param asset The asset that should be loaded
|
||||
* \param parent The parent of the loaded asset file or \c nullptr if the asset is a
|
||||
* root asset
|
||||
* \pre \p asset must not be a nullptr
|
||||
*/
|
||||
bool loadAsset(Asset* asset, Asset* parent);
|
||||
|
||||
/**
|
||||
* Unload the provided \p asset by removing all information about it from the Lua
|
||||
* state and placing the asset onto the deletion queue. Please note that the asset
|
||||
* will not actually get destroyed until the next #update call to the AssetManager.
|
||||
*
|
||||
* \param asset The asset that should get unloaded
|
||||
* \pre \p asset must not be a nullptr
|
||||
*/
|
||||
void unloadAsset(Asset* asset);
|
||||
|
||||
/**
|
||||
* This function calls the `onInitialize` function that was specified in the file of
|
||||
* the provided \p asset.
|
||||
*
|
||||
* \param asset The asset file whose `onInitialize` function should be called
|
||||
*/
|
||||
void callOnInitialize(Asset* asset) const;
|
||||
|
||||
/**
|
||||
* This function calls the `onDeinitialize` function that was specified in the file of
|
||||
* the provided \p asset.
|
||||
*
|
||||
* \param asset The asset file whose `onDeinitialize` function should be called
|
||||
*/
|
||||
void callOnDeinitialize(Asset* asset) const;
|
||||
|
||||
private:
|
||||
/// Creates and registers all of the callback functions that the asset is expected to
|
||||
/// call in the file, for example the `localResource`, `require`, etc.
|
||||
void setUpAssetLuaTable(Asset* asset);
|
||||
|
||||
/// Returns the loaded Asset by either trying to load the asset at the provided path
|
||||
/// or returning a previously loaded copy
|
||||
Asset* retrieveAsset(const std::filesystem::path& path);
|
||||
|
||||
/// Setup the asset table of the provided asset in the shared Lua state
|
||||
void setCurrentAsset(Asset* asset);
|
||||
|
||||
/// Takes the asset path, determines the type of path (relative to base, relative to
|
||||
/// root or absolute and returns fully formed path
|
||||
std::filesystem::path generateAssetPath(const std::filesystem::path& baseDirectory,
|
||||
const std::string& assetPath) const;
|
||||
|
||||
//
|
||||
// Assets
|
||||
//
|
||||
|
||||
/// The authoritative list of all assets loaded through the AssetManager
|
||||
std::vector<std::unique_ptr<Asset>> _assets;
|
||||
|
||||
/// A list of all root assets that have been loaded directly by the `add` function
|
||||
std::vector<Asset*> _rootAssets;
|
||||
|
||||
/// This list contains all of the assets that are queued to be loading in the next
|
||||
/// update call
|
||||
std::unordered_set<std::string> _assetAddQueue;
|
||||
|
||||
/// The list contains all of the assets that should be removed in the next update call
|
||||
std::unordered_set<std::string> _assetRemoveQueue;
|
||||
|
||||
/// This list contains all assets that need to be initialized in the next update call
|
||||
std::vector<Asset*> _toBeInitialized;
|
||||
|
||||
/// This list contains all of the assets that will be deleted in the next update call
|
||||
std::vector<std::unique_ptr<Asset>> _toBeDeleted;
|
||||
|
||||
//
|
||||
// ResourceSynchronizations
|
||||
//
|
||||
|
||||
/// Collection that stores the assets that have requested each ResourceSynchronization
|
||||
struct SyncItem {
|
||||
std::unique_ptr<ResourceSynchronization> synchronization;
|
||||
std::vector<Asset*> assets;
|
||||
};
|
||||
/// Authoritative list over all ResourceSynchronizations that have been requested by
|
||||
/// any asset
|
||||
std::unordered_map<std::string, std::unique_ptr<SyncItem>> _synchronizations;
|
||||
/// The list of ResourceSynchronizations that were not finished in the last update
|
||||
/// call
|
||||
std::vector<SyncItem*> _unfinishedSynchronizations;
|
||||
|
||||
//
|
||||
// Other values
|
||||
//
|
||||
|
||||
/// The location of the asset root directory
|
||||
std::filesystem::path _assetRootDirectory;
|
||||
|
||||
/// The Lua state that is used for all asset initialization
|
||||
ghoul::lua::LuaState* _luaState = nullptr;
|
||||
|
||||
// References to the onInitialize and the onDeinitialize functions for each Asset
|
||||
std::unordered_map<Asset*, std::vector<int>> _onInitializeFunctionRefs;
|
||||
std::unordered_map<Asset*, std::vector<int>> _onDeinitializeFunctionRefs;
|
||||
|
||||
int _assetsTableRef = 0;
|
||||
};
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
@@ -28,267 +28,442 @@
|
||||
#include <ghoul/misc/boolean.h>
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
// @TODO: This class is a diamond-of-death; maybe some redesign to make the things into
|
||||
// components, rather than inheritance?
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4250)
|
||||
#endif
|
||||
#include <chrono>
|
||||
|
||||
namespace openspace {
|
||||
|
||||
namespace curlfunctions {
|
||||
size_t writeCallback(char* ptr, size_t size, size_t nmemb, void* userData);
|
||||
|
||||
int progressCallback(void* userData, int64_t nTotalDownloadBytes,
|
||||
int64_t nDownloadedBytes, int64_t nTotalUploadBytes, int64_t nUploadBytes);
|
||||
|
||||
size_t headerCallback(char* ptr, size_t size, size_t nmemb, void* userData);
|
||||
}
|
||||
|
||||
// Synchronous http request
|
||||
/**
|
||||
* This class performs a synchronous HTTP request to the provided URL. Any result that is
|
||||
* returned based on this request is returned through three callback functions that can be
|
||||
* registered using the #onHeader, #onProgress, and #onData functions. Calling these
|
||||
* functions will overwrite any previously registered handler.
|
||||
* The ProgressCallback can be used to stop the download if the handler returns \c false.
|
||||
*
|
||||
* The workflow for this class:
|
||||
* 1. Create a new object with the URL that points to the location from which the data
|
||||
* should be loaded
|
||||
* 2. Register the callbacks that are needed (at least the #onData callback)
|
||||
* 3. Start the download with the #perform function
|
||||
*/
|
||||
class HttpRequest {
|
||||
public:
|
||||
enum class ReadyState : unsigned int {
|
||||
Unsent,
|
||||
Loading,
|
||||
ReceivedHeader,
|
||||
Fail,
|
||||
Success
|
||||
};
|
||||
/**
|
||||
* This callback is called every time there is progress to report for the download. It
|
||||
* transmits currently downloaded number of bytes (which can be 0 if the download
|
||||
* hasn't started yet) and the total number of bytes if that value is known. The
|
||||
* return value determines if the download should continue (if the function returns
|
||||
* \c true) or if it should abort (if \c false is returned).
|
||||
*
|
||||
* \param downloadedBytes The number of bytes that have been downloaded thus far or 0
|
||||
* if the download hasn't started yet
|
||||
* \param totalBytes The total number of bytes for the download if it is known, or a
|
||||
* std::nullopt of the total size is unknown
|
||||
* \return \c true if the download should continue or \c false if it should be aborted
|
||||
*/
|
||||
using ProgressCallback = std::function<
|
||||
bool(size_t downloadedBytes, std::optional<size_t> totalBytes)
|
||||
>;
|
||||
|
||||
struct Progress {
|
||||
bool totalBytesKnown = false;
|
||||
size_t totalBytes = 0;
|
||||
size_t downloadedBytes = 0;
|
||||
};
|
||||
/**
|
||||
* This callback is executed every time a chunk of data arrived for the download. The
|
||||
* parameters point to the buffer of this new incoming data and the number of bytes
|
||||
* that have arrived. The buffer pointed to will most likely only be valid during the
|
||||
* time of the callback and it is the callbacks responsibility to store the contents
|
||||
* of the buffer before the callback returns. If the return value is \c true, the
|
||||
* download continues, if it is \c false, this signals to the library that an error
|
||||
* has occurred from which recovery is not possible.
|
||||
*
|
||||
* \param buffer The pointer to the beginning of the buffer where the new incoming
|
||||
* data is located. This buffer is only valid during the execution of this
|
||||
* callback and the contents of the buffer should be copied to a different
|
||||
* location
|
||||
* \param size The number of bytes that are contained in the \p buffer
|
||||
* \return \c true if the download should continue or \c false if it should be aborted
|
||||
*/
|
||||
using DataCallback = std::function<bool(char* buffer, size_t size)>;
|
||||
|
||||
struct Data {
|
||||
char* buffer;
|
||||
size_t size;
|
||||
};
|
||||
/**
|
||||
* This callback is executed when the header of an HTTP request is received
|
||||
* successfully. The provided buffer and size contain the contents of the header field
|
||||
* for the response. The buffer pointed to will most likely only be valid during the
|
||||
* time of the callback and it is the callbacks responsibility to store the contents
|
||||
* of the buffer before the callback returns. If the return value is \c true, the
|
||||
* download continues, if it is \c false, this signals to the library that an error
|
||||
* has occurred from which recovery is not possible. If this function returns
|
||||
* \c false, it will cause the main download to not start at all.
|
||||
*
|
||||
* \param buffer The pointer to the beginning of the buffer where the header
|
||||
* information is located. This buffer is only valid during the execution of
|
||||
* this callback and the contents of the buffer should be copied to a different
|
||||
* location
|
||||
* \param size The number of bytes that are contained in the \p buffer
|
||||
* \return \c true if the download should continue or \c false if it should be aborted
|
||||
*/
|
||||
using HeaderCallback = std::function<bool(char* buffer, size_t size)>;
|
||||
|
||||
struct Header {
|
||||
char* buffer;
|
||||
size_t size;
|
||||
};
|
||||
/**
|
||||
* Creates a new HttpRequest object that will try to download the contents at the
|
||||
* provided \p url.
|
||||
*
|
||||
* \param url The URL that should be requested by this HttpRequest
|
||||
*
|
||||
* \pre \p url must not be empty
|
||||
*/
|
||||
explicit HttpRequest(std::string url);
|
||||
|
||||
using ReadyStateChangeCallback = std::function<void(ReadyState)>;
|
||||
|
||||
// ProgressCallback: Return non-zero value to cancel download.
|
||||
using ProgressCallback = std::function<int(Progress)>;
|
||||
|
||||
// DataCallback: Return number of bytes successfully stored.
|
||||
// If this does not match the data buffer sice reported in Data,
|
||||
// the request will fail.
|
||||
using DataCallback = std::function<size_t(Data)>;
|
||||
|
||||
// HeaderCallback: Return number of bytes successfully stored.
|
||||
// If this does not match the data buffer sice reported in Header,
|
||||
// the request will fail.
|
||||
using HeaderCallback = std::function<size_t(Header)>;
|
||||
|
||||
struct RequestOptions {
|
||||
int requestTimeoutSeconds; // 0 for no timeout
|
||||
};
|
||||
|
||||
HttpRequest(std::string url);
|
||||
|
||||
void onReadyStateChange(ReadyStateChangeCallback cb);
|
||||
/**
|
||||
* Registers a callback that will be called when the header for the request has been
|
||||
* transmitted successfully. The contents of the header will be passed into the
|
||||
* callback and the callback returns whether the request should proceed or be aborted.
|
||||
*
|
||||
* \param cb The callback that should be registered. This will silently replace any
|
||||
* previously registered callback
|
||||
*/
|
||||
void onHeader(HeaderCallback cb);
|
||||
|
||||
/**
|
||||
* Registers a callback that will be called whenever there is progress to be reported
|
||||
* on the transfer of the request's body. The callback will receive information about
|
||||
* the number of bytes that have been downloaded and the total number of bytes that
|
||||
* should be downloaded to complete the request. This information might not always be
|
||||
* available. The callback's return value determines whether the request should
|
||||
* continue or be aborted.
|
||||
*
|
||||
* \param cb The callback that should be registered. This will silently replace any
|
||||
* previously registered callback
|
||||
*/
|
||||
void onProgress(ProgressCallback cb);
|
||||
|
||||
/**
|
||||
* Registers a callback that will be called whenever there is new data that has been
|
||||
* received from the request. It is this callback's responsibility to store that data
|
||||
* in a place that is persistent across multiple calls to the callback, usually by
|
||||
* storing it in an external buffer and appending to it. The callback can return
|
||||
* whether the download should proceed (by returning \c true) or be aborted (by
|
||||
* returning \c false).
|
||||
*
|
||||
* \param cb The callback that should be registered. This will silently replace any
|
||||
* previously registered callback
|
||||
*/
|
||||
void onData(DataCallback cb);
|
||||
|
||||
void perform(RequestOptions opt);
|
||||
/**
|
||||
* Performs the request to the URL provided in the constructor. As this request is
|
||||
* handled synchronously, this function will only return once the request has been
|
||||
* completed successfully or failed. During this call, the registered callbacks will
|
||||
* be called repeatedly until the request finishes. This function returns whether the
|
||||
* request was completed successfully or failed.
|
||||
*
|
||||
* \param timeout The amount of time the request will wait before aborting due to the
|
||||
* server not responding. If this value is 0, there is no timeout on the
|
||||
* request.
|
||||
*
|
||||
* \return \c true if the request completed successfully, \c false otherwise
|
||||
*/
|
||||
bool perform(std::chrono::milliseconds timeout = std::chrono::milliseconds(0));
|
||||
|
||||
/**
|
||||
* Returns the URL that was passed into the constructor of this HttpRequest.
|
||||
*
|
||||
* \return The URL that was passed into the constructor of this HttpRequest
|
||||
*/
|
||||
const std::string& url() const;
|
||||
|
||||
private:
|
||||
void setReadyState(ReadyState state);
|
||||
|
||||
std::string _url;
|
||||
|
||||
ReadyStateChangeCallback _onReadyStateChange;
|
||||
ProgressCallback _onProgress;
|
||||
DataCallback _onData;
|
||||
/// The callback that will be called when the header was received successfully
|
||||
HeaderCallback _onHeader;
|
||||
|
||||
ReadyState _readyState;
|
||||
Progress _progress;
|
||||
/// The callback that will be called when there is progress to be reported
|
||||
ProgressCallback _onProgress;
|
||||
|
||||
friend size_t curlfunctions::writeCallback(char* ptr, size_t size, size_t nmemb,
|
||||
void* userData);
|
||||
/// The callback that will be called when there is data to be stored away
|
||||
DataCallback _onData;
|
||||
|
||||
friend int curlfunctions::progressCallback(void* userData,
|
||||
int64_t nTotalDownloadBytes,
|
||||
int64_t nDownloadedBytes, int64_t nTotalUploadBytes, int64_t nUploadBytes);
|
||||
|
||||
friend size_t curlfunctions::headerCallback(char* ptr, size_t size, size_t nmemb,
|
||||
void* userData);
|
||||
/// The URL that this HttpRequest is going to request
|
||||
std::string _url;
|
||||
};
|
||||
|
||||
/**
|
||||
* This abstract base class uses the HttpRequest class to perform an asynchronous
|
||||
* download. Every subclass needs to implement at least the #handleData function that will
|
||||
* be called every time a chunk of data has been received from the request. The download
|
||||
* is started through the #start function and it is possible to turn this into a
|
||||
* synchronous download by executing the #wait function directly afterwards. If a
|
||||
* HttpRequest::ProgressCallback has been registered through the #onProgress function,
|
||||
* that callback is called every time the download some progress to report.
|
||||
*/
|
||||
class HttpDownload {
|
||||
public:
|
||||
using ProgressCallback = std::function<bool(HttpRequest::Progress)>;
|
||||
using HeaderCallback = std::function<bool(HttpRequest::Header)>;
|
||||
/**
|
||||
* Creates a new HttpDownload that will start to download the file pointed to by the
|
||||
* \param url parameter as soon as the download is #start ed.
|
||||
*
|
||||
* \param url The URL that should be downloaded by this HttpDownload
|
||||
*
|
||||
* \pre \p url must not be empty
|
||||
*/
|
||||
explicit HttpDownload(std::string url);
|
||||
|
||||
HttpDownload();
|
||||
HttpDownload(HttpDownload&& d) = default;
|
||||
HttpDownload& operator=(HttpDownload&&) = default;
|
||||
virtual ~HttpDownload() = default;
|
||||
void onProgress(ProgressCallback progressCallback);
|
||||
void onHeader(HeaderCallback headerCallback);
|
||||
bool hasStarted() const;
|
||||
/**
|
||||
* Virtual destructor that will cancel the ongoing download and block until the
|
||||
* download is successfully canceled.
|
||||
*/
|
||||
virtual ~HttpDownload();
|
||||
|
||||
/**
|
||||
* Registers a callback that will be called whenever there is progress to be reported
|
||||
* on the file's download. The callback will receive information about the number of
|
||||
* bytes that have been downloaded and the total number of bytes that should be
|
||||
* downloaded. This information might not always be available. The callback's return
|
||||
* value determines whether the request should continue or be aborted.
|
||||
*
|
||||
* \param progressCallback The callback that should be registered. This will silently
|
||||
* replace any previously registered callback
|
||||
*/
|
||||
void onProgress(HttpRequest::ProgressCallback progressCallback);
|
||||
|
||||
/**
|
||||
* Starts the asynchronous download of the file by starting a new thread that will
|
||||
* take care of the download, meaning that this function will return almost
|
||||
* instantaneously. If the HttpDownload is already downloading a file this function
|
||||
* does nothing.
|
||||
*
|
||||
* \param timeout The number of milliseconds that the download will be kept alive
|
||||
* while waiting for a reply from the server. If this value is 0, the
|
||||
* connection will never time out
|
||||
*/
|
||||
void start(std::chrono::milliseconds timeout = std::chrono::milliseconds(0));
|
||||
|
||||
/**
|
||||
* Cancels the ongoing download. Because of the underlying library that is used, the
|
||||
* transfer will only be aborted the next time any piece of data is received or the
|
||||
* library reports any progress.
|
||||
*/
|
||||
void cancel();
|
||||
|
||||
/**
|
||||
* This function will wait until the download has completed and will return the
|
||||
* success of the download back to the caller.
|
||||
*
|
||||
* \return \c true if the downloaded succeeded or \c false if the download failed
|
||||
*/
|
||||
bool wait();
|
||||
|
||||
/**
|
||||
* Returns \c true if the download has completed and it failed, or \c false if either
|
||||
* the download is till ongoing or is finished and has succeeded.
|
||||
*
|
||||
* \return Whether the download has completed and it failed
|
||||
*/
|
||||
bool hasFailed() const;
|
||||
|
||||
/**
|
||||
* Returns \c true if the download has completed successfully , or \c false if either
|
||||
* the download is till ongoing or is finished and has failed.
|
||||
*
|
||||
* \return Whether the download has completed successfully
|
||||
*/
|
||||
bool hasSucceeded() const;
|
||||
|
||||
protected:
|
||||
virtual size_t handleData(HttpRequest::Data d) = 0;
|
||||
virtual bool initDownload() = 0;
|
||||
virtual bool deinitDownload() = 0;
|
||||
|
||||
bool callOnProgress(HttpRequest::Progress p);
|
||||
void markAsStarted();
|
||||
void markAsSuccessful();
|
||||
void markAsFailed();
|
||||
|
||||
private:
|
||||
ProgressCallback _onProgress;
|
||||
bool _started = false;
|
||||
bool _failed = false;
|
||||
bool _successful = false;
|
||||
};
|
||||
|
||||
class SyncHttpDownload : public virtual HttpDownload {
|
||||
public:
|
||||
SyncHttpDownload(std::string url);
|
||||
SyncHttpDownload(SyncHttpDownload&& d) = default;
|
||||
SyncHttpDownload& operator=(SyncHttpDownload&&) = default;
|
||||
virtual ~SyncHttpDownload() = default;
|
||||
void download(HttpRequest::RequestOptions opt);
|
||||
|
||||
/**
|
||||
* Returns the URL that was passed into the constructor of this HttpDownload.
|
||||
*
|
||||
* \return The URL that was passed into the constructor of this HttpDownload
|
||||
*/
|
||||
const std::string& url() const;
|
||||
|
||||
protected:
|
||||
HttpRequest _httpRequest;
|
||||
};
|
||||
/**
|
||||
* This abstract function has to be implemented by any concrete subclass to handle an
|
||||
* incoming chunk of data from the download. The parameters point to the \p buffer of
|
||||
* this new incoming data and the number of bytes that have arrived. The buffer
|
||||
* pointed to will most likely only be valid during the time of the callback and it is
|
||||
* the callbacks responsibility to store the contents of the buffer before the
|
||||
* callback returns. If the return value is \c true, the download continues, if it is
|
||||
* \c false, this signals to the library that an error has occurred from which
|
||||
* recovery is not possible. This function will be called on a different thread from
|
||||
* the one that called the #start method.
|
||||
*
|
||||
* \param buffer The beginning of the buffer of this chunk of data
|
||||
* \param size The number of bytes that the \p buffer contains
|
||||
*
|
||||
* \return The implementation should return \c true if the downloading should continue
|
||||
* and \c false if the handling of the data caused some error that the
|
||||
* subclass is incapable of recovering from
|
||||
*/
|
||||
virtual bool handleData(char* buffer, size_t size) = 0;
|
||||
|
||||
class AsyncHttpDownload : public virtual HttpDownload {
|
||||
public:
|
||||
AsyncHttpDownload(std::string url);
|
||||
AsyncHttpDownload(AsyncHttpDownload&& d);
|
||||
virtual ~AsyncHttpDownload() = default;
|
||||
void start(HttpRequest::RequestOptions opt);
|
||||
void cancel();
|
||||
void wait();
|
||||
/**
|
||||
* This function is called before the downloading starts and can be used by subclasses
|
||||
* to perform one-time setup functions, such as opening a file, reserving a block of
|
||||
* storage, etc. This function guaranteed to be only called once per HttpDownload.
|
||||
* The return value determines if the setup operation completed successfully or if an
|
||||
* error occurred that will cause the download to be terminated. This function will be
|
||||
* called on a different thread from the one that called the #start method.
|
||||
*
|
||||
* \return \c true if the setup completed successfully and \c false if the setup
|
||||
* failed unrecoverably
|
||||
*/
|
||||
virtual bool setup();
|
||||
|
||||
const std::string& url() const;
|
||||
|
||||
protected:
|
||||
void download(HttpRequest::RequestOptions opt);
|
||||
/**
|
||||
* This function is called after the downloading has finished and before a potential
|
||||
* call to #wait is performed. This function can be used by a subclass to perform
|
||||
* one-time operations that are required when the downloading fininshes, such as
|
||||
* closing file handles, committing some memory etc. The return value of this function
|
||||
* signals whether the teardown completed successfully. This function will be called
|
||||
* on a different thread from the one that called the #start method.
|
||||
*
|
||||
* \return \c true if the teardown completed successfully and \c false if it failed
|
||||
*/
|
||||
virtual bool teardown();
|
||||
|
||||
private:
|
||||
HttpRequest _httpRequest;
|
||||
std::thread _downloadThread;
|
||||
std::mutex _conditionMutex;
|
||||
std::condition_variable _downloadFinishCondition;
|
||||
/// The callback that will be called whenever there is some progress to be reported
|
||||
HttpRequest::ProgressCallback _onProgress;
|
||||
|
||||
/// Value indicating whether the HttpDownload is currently downloading a file
|
||||
bool _isDownloading = false;
|
||||
|
||||
/// Value indicating whether the download is finished
|
||||
bool _isFinished = false;
|
||||
|
||||
/// Value indicated whether the download was successful
|
||||
bool _isSuccessful = false;
|
||||
|
||||
/// Marker telling the downloading thread that the download should be cancelled
|
||||
bool _shouldCancel = false;
|
||||
std::mutex _stateChangeMutex;
|
||||
|
||||
/// The HttpRequest class that will be used for the download
|
||||
HttpRequest _httpRequest;
|
||||
|
||||
/// The thread that contains the HttpRequest to download the file
|
||||
std::thread _downloadThread;
|
||||
|
||||
/// This condition variable is used by the #wait function to be able to wait for
|
||||
/// completion of the downloading thread
|
||||
std::condition_variable _downloadFinishCondition;
|
||||
};
|
||||
|
||||
class HttpFileDownload : public virtual HttpDownload {
|
||||
/**
|
||||
* This specific subclass of the HttpDownload downloads the contents of the provided URL
|
||||
* into a file on disk. By default, an existing file will not be overwritten and will
|
||||
* cause the download to fail. This behavior can be overwritten through a parameter in the
|
||||
* constructor of this class.
|
||||
*/
|
||||
class HttpFileDownload : public HttpDownload {
|
||||
public:
|
||||
BooleanType(Overwrite);
|
||||
|
||||
HttpFileDownload() = default;
|
||||
HttpFileDownload(std::string destination, Overwrite = Overwrite::No);
|
||||
/**
|
||||
* Constructor that will create a HttpFileDownload which will download the contents of
|
||||
* the provided \p url to the \p destinationPath. If the \p destinationPath already
|
||||
* contains a file and \p overwrite is Overwrite::No, the download will fail; if it is
|
||||
* Overwrite::Yes, the existing content at the \p destinationPath will be overwritten.
|
||||
*/
|
||||
HttpFileDownload(std::string url, std::filesystem::path destinationPath,
|
||||
Overwrite overwrite = Overwrite::No);
|
||||
|
||||
/**
|
||||
* This destructor will cancel any ongoing download and wait for its completion, so it
|
||||
* might not block for a short amount of time.
|
||||
*/
|
||||
virtual ~HttpFileDownload() = default;
|
||||
|
||||
const std::string& destination() const;
|
||||
/**
|
||||
* Returns the path where the contents of the URL provided in the constructor will be
|
||||
* saved to.
|
||||
*
|
||||
* \return The path where URL will be downloaded to
|
||||
*/
|
||||
std::filesystem::path destination() const;
|
||||
|
||||
protected:
|
||||
bool initDownload() override;
|
||||
bool deinitDownload() override;
|
||||
size_t handleData(HttpRequest::Data d) override;
|
||||
private:
|
||||
/// Will create all directories that are necessary to reach _destination and then
|
||||
/// fight with other HttpFileDownloads to get one of a limited number of file handles
|
||||
/// to open _file
|
||||
bool setup() override;
|
||||
|
||||
static std::mutex _directoryCreationMutex;
|
||||
/// Closes the _file and returns the handle back to the pool of available handles
|
||||
bool teardown() override;
|
||||
|
||||
/// Stores the chunk of data into the _file handle
|
||||
bool handleData(char* buffer, size_t size) override;
|
||||
|
||||
/// A flag whether this HttpFileDownload got a handle from the limited supply of
|
||||
/// handles. This limit is used to prevent all HttpFileDownloads from getting file
|
||||
/// handles from the operating system as that resource is limited and downloads would
|
||||
/// fail unrecoverably if no handles are available. So we limit the maximum number and
|
||||
/// if that number is exceeded, the HttpFileDownload will wait until a handle is
|
||||
/// available.
|
||||
std::atomic_bool _hasHandle = false;
|
||||
|
||||
private:
|
||||
std::string _destination;
|
||||
bool _overwrite;
|
||||
/// The destination path where the contents of the URL provided in the constructor
|
||||
/// will be saved to
|
||||
std::filesystem::path _destination;
|
||||
|
||||
/// The file handle to the _destination used to save incoming chunks
|
||||
std::ofstream _file;
|
||||
|
||||
static const int MaxFilehandles = 35;
|
||||
static std::atomic_int nCurrentFilehandles;
|
||||
/// Mutex that will be prevent multiple HttpFileDownloads to simultaneously try to
|
||||
/// create the necessary intermediate directories, which would cause issues
|
||||
static std::mutex _directoryCreationMutex;
|
||||
|
||||
/// The maximum number of file handles that all HttpFileDownloads combined can use up
|
||||
static constexpr const int MaxFileHandles = 32;
|
||||
|
||||
/// Stores the number of currently open file handles across all HttpFileDownloads
|
||||
static std::atomic_int nCurrentFileHandles;
|
||||
};
|
||||
|
||||
class HttpMemoryDownload : public virtual HttpDownload {
|
||||
/**
|
||||
* This concerete HttpDownload subclass downloads the contents of the URL passed into the
|
||||
* constructor into a buffer of memory that can be retrieve. Please note that that buffer
|
||||
* should only be used accessed once the HttpDownload::hasFinished function returns
|
||||
* \c true.
|
||||
*/
|
||||
class HttpMemoryDownload : public HttpDownload {
|
||||
public:
|
||||
HttpMemoryDownload() = default;
|
||||
HttpMemoryDownload(HttpMemoryDownload&& d) = default;
|
||||
HttpMemoryDownload& operator=(HttpMemoryDownload&&) = default;
|
||||
/**
|
||||
* Creates an instance of a HttpMemoryDownload that will download the contents of the
|
||||
* \p url into memory
|
||||
*
|
||||
* \param url The URL whose contents should be downloaded
|
||||
*/
|
||||
explicit HttpMemoryDownload(std::string url);
|
||||
|
||||
/**
|
||||
* This destructor will cancel any ongoing download and wait for its completion, so it
|
||||
* might not block for a short amount of time.
|
||||
*/
|
||||
virtual ~HttpMemoryDownload() = default;
|
||||
|
||||
/**
|
||||
* Returns a reference to the buffer that is used to store the contents of the URL
|
||||
* passed in the constructor. Please observe that while the HttpDownload::hasFinished
|
||||
* method returns \c false, this buffer will be changed by a different thread and
|
||||
* access is not thread-safe. After that function returns \c true, it is safe to
|
||||
* access the buffer.
|
||||
*
|
||||
* \return A reference to the buffer used to hold the contents of the URL
|
||||
*/
|
||||
const std::vector<char>& downloadedData() const;
|
||||
|
||||
protected:
|
||||
bool initDownload() override;
|
||||
bool deinitDownload() override;
|
||||
size_t handleData(HttpRequest::Data d) override;
|
||||
|
||||
private:
|
||||
std::vector<char> _downloadedData;
|
||||
};
|
||||
/// Stores each downloaded chunk into the stored buffer
|
||||
bool handleData(char* buffer, size_t size) override;
|
||||
|
||||
// Synchronous download to memory
|
||||
class SyncHttpMemoryDownload : public SyncHttpDownload, public HttpMemoryDownload {
|
||||
public:
|
||||
SyncHttpMemoryDownload(std::string url);
|
||||
virtual ~SyncHttpMemoryDownload() = default;
|
||||
};
|
||||
|
||||
// Synchronous download to file
|
||||
class SyncHttpFileDownload : public SyncHttpDownload, public HttpFileDownload {
|
||||
public:
|
||||
SyncHttpFileDownload(
|
||||
std::string url,
|
||||
std::string destinationPath,
|
||||
HttpFileDownload::Overwrite = Overwrite::No
|
||||
);
|
||||
virtual ~SyncHttpFileDownload() = default;
|
||||
};
|
||||
|
||||
// Asynchronous download to memory
|
||||
class AsyncHttpMemoryDownload : public AsyncHttpDownload, public HttpMemoryDownload {
|
||||
public:
|
||||
AsyncHttpMemoryDownload(std::string url);
|
||||
virtual ~AsyncHttpMemoryDownload() = default;
|
||||
};
|
||||
|
||||
// Asynchronous download to file
|
||||
class AsyncHttpFileDownload : public AsyncHttpDownload, public HttpFileDownload {
|
||||
public:
|
||||
AsyncHttpFileDownload(
|
||||
std::string url,
|
||||
std::string destinationPath,
|
||||
HttpFileDownload::Overwrite = Overwrite::No
|
||||
);
|
||||
virtual ~AsyncHttpFileDownload() = default;
|
||||
/// The buffer where the downloaded chunks are accumulated
|
||||
std::vector<char> _buffer;
|
||||
};
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
|
||||
#endif // __OPENSPACE_CORE___HTTPREQUEST___H__
|
||||
|
||||
@@ -26,11 +26,8 @@
|
||||
#define __OPENSPACE_CORE___RESOURCESYNCHRONIZATION___H__
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace ghoul { class Dictionary; }
|
||||
|
||||
@@ -38,8 +35,152 @@ namespace openspace {
|
||||
|
||||
namespace documentation { struct Documentation; }
|
||||
|
||||
/**
|
||||
* The ResourceSynchronization class handles the download of persistent datasets, meaning
|
||||
* that the contents of the data is only downloaded once at the beginning of the
|
||||
* application. A ResourceSynchronization is created through the #createFromDictionary
|
||||
* function, whose dictionary must contain at least a \c Type value that specifies which
|
||||
* type of ResourceSynchronization should be create. Any type that is registered to the
|
||||
* global factory is a valid type here.
|
||||
* A ResourceSynchronization state can be in one of four states that can be queried
|
||||
* through the #isSyncing, #isResolved, and #isRejected functions. The available states
|
||||
* are:
|
||||
* \c Unsynchronized (#isSyncing = false, #isResolved = false, #isRejected = false),
|
||||
* \c Syncing (#isSyncing = true, #isResolved = false, #isRejected = false),
|
||||
* \c Resolved (#isSyncing = false, #isResolved = true, #isRejected = false),
|
||||
* \c Rejected (#isSyncing = false, #isResolved = false, #isRejected = true)
|
||||
*/
|
||||
class ResourceSynchronization {
|
||||
public:
|
||||
/**
|
||||
* Creates a new ResourceSynchronization based on the \p dictionary information that
|
||||
* is passed into this function. The dictionary must contain at least a \c Type, an
|
||||
* \c Identifier, and a \c Name, with other optional parameters depending on the
|
||||
* specific subtype of ResourceSynchronization class is is specified through the
|
||||
* provided \c Type.
|
||||
*
|
||||
* \param dictionary The dictionary containing the parameters with which to choose the
|
||||
* specific type of ResourceSynchronization and all the necessary parameters to
|
||||
* initialize said ResourceSynchronization
|
||||
*
|
||||
* \throw SpecificationError If the \p dictionary does not contain a \c Type, an
|
||||
* \c Identifier, and a \c Name
|
||||
*/
|
||||
static std::unique_ptr<ResourceSynchronization> createFromDictionary(
|
||||
const ghoul::Dictionary& dictionary);
|
||||
|
||||
/**
|
||||
* Generates a unique identifying string for the dictionary that is based on the
|
||||
* \c Type and the \c Identifier values of the passed \p dictionary. All other
|
||||
* parameters are ignored, but as long as the \c Type and/or the \c Identifier values
|
||||
* differ, the resulting string will be different.
|
||||
*
|
||||
* \param dictionary The dictionary containing the \c Type and the \c Identifier used
|
||||
* to create a unique identifier
|
||||
*
|
||||
* \throw SpecificationError If the \p dictionary does not contain a \c Type, an
|
||||
* \c Identifier, and a \c Name
|
||||
*/
|
||||
static std::string generateUid(const ghoul::Dictionary& dictionary);
|
||||
|
||||
/// Defaulted virtual constructor
|
||||
virtual ~ResourceSynchronization() = default;
|
||||
|
||||
/**
|
||||
* Returns the location to which files downloaded through this ResourceSynchronization
|
||||
* are saved.
|
||||
*
|
||||
* \return The location for files created by this class
|
||||
*/
|
||||
virtual std::filesystem::path directory() const = 0;
|
||||
|
||||
/// Starts the synchronization for this ResourceSynchronization
|
||||
virtual void start() = 0;
|
||||
|
||||
/// Cancels any ongoing synchronization of this ResourceSynchronization
|
||||
virtual void cancel() = 0;
|
||||
|
||||
/**
|
||||
* Returns the number of bytes that have already been synchronized or 0 if the
|
||||
* synchronization hasn't started yet. This number always will only contain the number
|
||||
* of bytes of actual payload data, not any additional data transfers that some
|
||||
* subtypes might require.
|
||||
*
|
||||
* \return The number of synchronized bytes
|
||||
*/
|
||||
size_t nSynchronizedBytes() const;
|
||||
|
||||
/**
|
||||
* Returns the number of total bytes that ought to be synchronized for this
|
||||
* ResourceSynchronization to be considered complete. If that number is not known
|
||||
* (yet), the returned value is 0. This number always will only contain the number of
|
||||
* bytes of actual payload data, not any additional data transfers that some subtypes
|
||||
* might require.
|
||||
*
|
||||
* \return The total number of required bytes
|
||||
*/
|
||||
size_t nTotalBytes() const;
|
||||
|
||||
/**
|
||||
* Returns \c true if the total number of bytes for this ResourceSynchronization is
|
||||
* known. Will return \c false otherwise. This number always will only contain the
|
||||
* number of bytes of actual payload data, not any additional data transfers that some
|
||||
* subtypes might require.
|
||||
*
|
||||
* \return The state whether the number of total bytes is known or not
|
||||
*/
|
||||
bool nTotalBytesIsKnown() const;
|
||||
|
||||
/**
|
||||
* Returns the unique identifier of this ResourceSynchronization.
|
||||
*
|
||||
* \return The unique identifier of this ResourceSynchronization
|
||||
*/
|
||||
const std::string& identifier() const;
|
||||
|
||||
/**
|
||||
* Returns the name of this ResourceSynchronization.
|
||||
*
|
||||
* \return The name of this ResourceSynchronization
|
||||
*/
|
||||
const std::string& name() const;
|
||||
|
||||
/**
|
||||
* Returns whether this ResourceSynchronization is currently syncing its files and has
|
||||
* not finished doing so.
|
||||
*
|
||||
* \return \c true if this object is currently synchronizing
|
||||
*/
|
||||
bool isSyncing() const;
|
||||
|
||||
/**
|
||||
* Returns whether this ResourceSynchronization has successfully finished
|
||||
* synchronizing all of its files. Once this has returned \c true, it will stay so
|
||||
* until the object is destroyed and it is guaranteed that no more files will be added
|
||||
* to the #directory.
|
||||
*
|
||||
* \return \c true if this object is finished synchronizing
|
||||
*/
|
||||
bool isResolved() const;
|
||||
|
||||
/**
|
||||
* Returns whether this ResourceSynchronization has failed to synchronizing all or any
|
||||
* of its files. Once this has returned \c true, it will stay so until the object is
|
||||
* destroyed. Some subclasses might try to download as many files as possible, but no
|
||||
* general guarantee is provided regarding the completeness of the download.
|
||||
*
|
||||
* \return \c true if this object has failed synchronizing one or more of the required
|
||||
* files
|
||||
*/
|
||||
bool isRejected() const;
|
||||
|
||||
static documentation::Documentation Documentation();
|
||||
|
||||
protected:
|
||||
/// Empty constructor that just sets the synchronization root
|
||||
ResourceSynchronization(std::filesystem::path synchronizationRoot);
|
||||
|
||||
/// Representation of the state that this object can be in
|
||||
enum class State {
|
||||
Unsynced,
|
||||
Syncing,
|
||||
@@ -47,49 +188,34 @@ public:
|
||||
Rejected
|
||||
};
|
||||
|
||||
using CallbackHandle = size_t;
|
||||
using StateChangeCallback = std::function<void(State)>;
|
||||
/// Creates a file next to the directory that indicates that this
|
||||
/// ResourceSynchronization has successfully synchronized its contents
|
||||
void createSyncFile() const;
|
||||
|
||||
static std::unique_ptr<ResourceSynchronization> createFromDictionary(
|
||||
const ghoul::Dictionary& dictionary);
|
||||
/// Returns whether the synchronization file create in #createSyncFile exists
|
||||
bool hasSyncFile() const;
|
||||
|
||||
ResourceSynchronization(const ghoul::Dictionary& dictionary);
|
||||
virtual ~ResourceSynchronization() = default;
|
||||
|
||||
virtual std::string directory() = 0;
|
||||
virtual void start() = 0;
|
||||
virtual void cancel() = 0;
|
||||
virtual void clear() = 0;
|
||||
|
||||
virtual size_t nSynchronizedBytes() = 0;
|
||||
virtual size_t nTotalBytes() = 0;
|
||||
virtual bool nTotalBytesIsKnown() = 0;
|
||||
virtual float progress();
|
||||
|
||||
State state() const;
|
||||
const std::string& name() const;
|
||||
bool isResolved() const;
|
||||
bool isRejected() const;
|
||||
bool isSyncing() const;
|
||||
CallbackHandle addStateChangeCallback(StateChangeCallback cb);
|
||||
void removeStateChangeCallback(CallbackHandle id);
|
||||
|
||||
static documentation::Documentation Documentation();
|
||||
|
||||
protected:
|
||||
void resolve();
|
||||
void reject();
|
||||
void reset();
|
||||
void begin();
|
||||
|
||||
private:
|
||||
void setState(State state);
|
||||
/// The internal identifier for this ResourceSynchronization. It is not enforced but
|
||||
/// advised that this identifier be different for all instances of the same subtype
|
||||
std::string _identifier;
|
||||
|
||||
/// The user-facing name of this ResourceSynchronization
|
||||
std::string _name;
|
||||
|
||||
/// The path to the root folder relative to which synchronization files are placed
|
||||
const std::filesystem::path _synchronizationRoot;
|
||||
|
||||
/// The current #State of this ResouceSynchronization
|
||||
std::atomic<State> _state = State::Unsynced;
|
||||
std::mutex _callbackMutex;
|
||||
CallbackHandle _nextCallbackId = 0;
|
||||
std::unordered_map<CallbackHandle, StateChangeCallback> _stateChangeCallbacks;
|
||||
|
||||
/// Contains the fact whether the total number of payload bytes is known
|
||||
std::atomic_bool _nTotalBytesKnown = false;
|
||||
|
||||
/// Contains the total number of payload bytes or 0 if that number is not known
|
||||
std::atomic_size_t _nTotalBytes = 0;
|
||||
|
||||
/// Contains the number of already synchronized payload bytes
|
||||
std::atomic_size_t _nSynchronizedBytes = 0;
|
||||
};
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2021 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_CORE___SYNCHRONIZATIONWATCHER___H__
|
||||
#define __OPENSPACE_CORE___SYNCHRONIZATIONWATCHER___H__
|
||||
|
||||
#include <openspace/util/resourcesynchronization.h>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace openspace {
|
||||
|
||||
/**
|
||||
* Delays callbacks of synchronization state changes to
|
||||
* when notify is called.
|
||||
*/
|
||||
class SynchronizationWatcher {
|
||||
public:
|
||||
using WatchHandle = size_t;
|
||||
|
||||
struct WatchData {
|
||||
std::weak_ptr<ResourceSynchronization> synchronization;
|
||||
ResourceSynchronization::CallbackHandle callbackHandle;
|
||||
};
|
||||
|
||||
struct NotificationData {
|
||||
std::weak_ptr<ResourceSynchronization> synchronization;
|
||||
ResourceSynchronization::State state;
|
||||
WatchHandle handle;
|
||||
ResourceSynchronization::StateChangeCallback callback;
|
||||
};
|
||||
|
||||
WatchHandle watchSynchronization(
|
||||
std::shared_ptr<ResourceSynchronization> synchronization,
|
||||
ResourceSynchronization::StateChangeCallback callback
|
||||
);
|
||||
|
||||
void unwatchSynchronization(WatchHandle watchHandle);
|
||||
|
||||
void notify();
|
||||
|
||||
private:
|
||||
std::mutex _mutex;
|
||||
std::unordered_map<WatchHandle, WatchData> _watchedSyncs;
|
||||
std::vector<NotificationData> _pendingNotifications;
|
||||
|
||||
WatchHandle nextWatchHandle = 0;
|
||||
};
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __OPENSPACE_CORE___SYNCHRONIZATIONWATCHER___H__
|
||||
@@ -49,7 +49,7 @@ public:
|
||||
SemanticVersion latestVersion();
|
||||
|
||||
private:
|
||||
std::unique_ptr<AsyncHttpMemoryDownload> _request;
|
||||
std::unique_ptr<HttpMemoryDownload> _request;
|
||||
std::optional<SemanticVersion> _latestVersion;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user