/***************************************************************************************** * * * OpenSpace * * * * Copyright (c) 2014-2023 * * * * 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___RESOURCESYNCHRONIZATION___H__ #define __OPENSPACE_CORE___RESOURCESYNCHRONIZATION___H__ #include #include #include namespace ghoul { class Dictionary; } 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 `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: * - `Unsynchronized` (#isSyncing = false, #isResolved = false, #isRejected = false) * - `Syncing` (#isSyncing = true, #isResolved = false, #isRejected = false) * - `Resolved` (#isSyncing = false, #isResolved = true, #isRejected = false) * - `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 `Type`, an * `Identifier`, and a `Name`, with other optional parameters depending on the * specific subtype of ResourceSynchronization class is is specified through the * provided `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 `Type`, an * `Identifier`, and a `Name` */ static std::unique_ptr createFromDictionary( const ghoul::Dictionary& dictionary); /** * Generates a unique identifying string for ResourceSynchronizaiton. */ virtual std::string generateUid() = 0; /// 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 `true` if the total number of bytes for this ResourceSynchronization is * known. Will return `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 `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 `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 `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 `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 `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, Resolved, Rejected }; /// Creates a file next to the directory that indicates that this /// ResourceSynchronization has successfully synchronized its contents void createSyncFile() const; /// Returns whether the synchronization file create in #createSyncFile exists bool hasSyncFile() const; /// 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::Unsynced; /// 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 #endif // __OPENSPACE_CORE___RESOURCESYNCHRONIZATION___H__