diff --git a/include/openspace/scene/assetmanager.h b/include/openspace/scene/assetmanager.h index 33a1d7b961..84a76a903b 100644 --- a/include/openspace/scene/assetmanager.h +++ b/include/openspace/scene/assetmanager.h @@ -64,7 +64,7 @@ public: void clearAllTargetAssets(); std::vector> allAssets(); scripting::LuaLibrary luaLibrary(); - + bool isDone(); private: std::shared_ptr tryLoadAsset(const std::string& path); bool tryInitializeAsset(Asset& asset); diff --git a/include/openspace/util/httprequest.h b/include/openspace/util/httprequest.h index 0a9f9c2819..e26c177998 100644 --- a/include/openspace/util/httprequest.h +++ b/include/openspace/util/httprequest.h @@ -28,10 +28,13 @@ #include #include +#include #include #include #include #include +#include +#include namespace openspace { @@ -100,48 +103,106 @@ private: RequestOptions _options; friend size_t curlfunctions::writeCallback( - char *ptr, - size_t size, - size_t nmemb, - void *userdata); + char *ptr, + size_t size, + size_t nmemb, + void *userdata); - friend int curlfunctions::progressCallback(void *clientp, - int64_t dltotal, - int64_t dlnow, - int64_t ultotal, - int64_t ulnow); + friend int curlfunctions::progressCallback( + void *clientp, + int64_t dltotal, + int64_t dlnow, + int64_t ultotal, + int64_t ulnow); }; - -class HttpMemoryDownload { -public: - HttpMemoryDownload(std::string url); - - void onReadyStateChange(HttpRequest::ReadyStateChangeCallback cb); - void onProgress(HttpRequest::ProgressCallback cb); - - void download(HttpRequest::RequestOptions opt); - - const std::vector& downloadedData(); + +class HttpDownloadInterface { +public: + virtual bool initDownload() = 0; + virtual bool deinitDownload() = 0; + virtual size_t handleData(HttpRequest::Data d) = 0; +}; + +class SyncHttpDownload : public virtual HttpDownloadInterface { +public: + SyncHttpDownload(std::string url); + void download(HttpRequest::RequestOptions opt); +protected: + HttpRequest _httpRequest; +}; + +class AsyncHttpDownload : public virtual HttpDownloadInterface { +public: + AsyncHttpDownload(std::string url); + virtual ~AsyncHttpDownload() = default; + void start(HttpRequest::RequestOptions opt); + void cancel(); + void wait(); +protected: + void download(HttpRequest::RequestOptions opt); private: HttpRequest _httpRequest; + + std::thread _downloadThread; + std::mutex _mutex; + std::condition_variable _downloadFinishCondition; + bool _started = false; + bool _shouldCancel = false; + bool _finished = false; + bool _successful = false; +}; + +class HttpFileDownload : public virtual HttpDownloadInterface { +public: + HttpFileDownload(std::string destination); +protected: + bool initDownload() override; + bool deinitDownload() override; + size_t handleData(HttpRequest::Data d) override; +private: + std::string _destination; + std::ofstream _file; +}; + +class HttpMemoryDownload : public virtual HttpDownloadInterface { +public: + const std::vector& downloadedData(); +protected: + bool initDownload() override; + bool deinitDownload() override; + size_t handleData(HttpRequest::Data d) override; +private: std::vector _downloadedData; }; -class HttpFileDownload { +// Synchronous download to memory +class SyncHttpMemoryDownload : public SyncHttpDownload, public HttpMemoryDownload { public: - HttpFileDownload(std::string url, std::string destinationPath); - - void onReadyStateChange(HttpRequest::ReadyStateChangeCallback cb); - void onProgress(HttpRequest::ProgressCallback cb); - - void download(HttpRequest::RequestOptions opt); - -private: - HttpRequest _httpRequest; - std::string _destination; + 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); + 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); + virtual ~AsyncHttpFileDownload() = default; }; - } // namespace openspace diff --git a/modules/sync/syncs/httpsynchronization.cpp b/modules/sync/syncs/httpsynchronization.cpp index 2df385eb13..732420d61f 100644 --- a/modules/sync/syncs/httpsynchronization.cpp +++ b/modules/sync/syncs/httpsynchronization.cpp @@ -112,14 +112,16 @@ void HttpSynchronization::start() { return; } - // TODO: Do this in a new thread! std::vector listUrls = fileListUrls(); - for (const auto& url : listUrls) { - if (trySyncFromUrl(url)) { - resolve(); - return; + _syncThread = std::thread([this, listUrls] { + for (const auto& url : listUrls) { + if (trySyncFromUrl(url)) { + resolve(); + return; + } } - } + //fail(); + }); } void HttpSynchronization::cancel() { @@ -150,9 +152,11 @@ bool HttpSynchronization::trySyncFromUrl(std::string listUrl) { HttpRequest::RequestOptions opt; opt.requestTimeoutSeconds = 0; - HttpMemoryDownload fileListDownload(listUrl); + SyncHttpMemoryDownload fileListDownload(listUrl); fileListDownload.download(opt); + // ... + const std::vector& buffer = fileListDownload.downloadedData(); std::istringstream fileList(std::string(buffer.begin(), buffer.end())); @@ -168,7 +172,7 @@ bool HttpSynchronization::trySyncFromUrl(std::string listUrl) { filename; std::thread t([opt, line, fileDestination]() { - HttpFileDownload fileDownload(line, fileDestination); + SyncHttpFileDownload fileDownload(line, fileDestination); fileDownload.download(opt); }); downloadThreads.push_back(std::move(t)); @@ -176,6 +180,7 @@ bool HttpSynchronization::trySyncFromUrl(std::string listUrl) { for (auto& t : downloadThreads) { t.join(); } + createSyncFile(); return true; } diff --git a/modules/sync/syncs/httpsynchronization.h b/modules/sync/syncs/httpsynchronization.h index 02a36d4e6d..1c9cbf506c 100644 --- a/modules/sync/syncs/httpsynchronization.h +++ b/modules/sync/syncs/httpsynchronization.h @@ -60,6 +60,8 @@ private: int _version; std::string _synchronizationRoot; std::vector _synchronizationRepositories; + + std::thread _syncThread; }; } // namespace openspace diff --git a/modules/sync/torrentclient.cpp b/modules/sync/torrentclient.cpp index 69f7527a59..86634583a2 100644 --- a/modules/sync/torrentclient.cpp +++ b/modules/sync/torrentclient.cpp @@ -90,13 +90,13 @@ void TorrentClient::pollAlerts() { _session->pop_alerts(&alerts); for (lt::alert const* a : alerts) { - LINFO(a->message()); + //LINFO(a->message()); // if we receive the finished alert or an error, we're done if (lt::alert_cast(a)) { - LINFO(a->message()); + //LINFO(a->message()); } if (lt::alert_cast(a)) { - LINFO(a->message()); + //LINFO(a->message()); } } } diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index f58ddbac39..123d28fb2b 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -1136,6 +1136,10 @@ void OpenSpaceEngine::postSynchronizationPreDraw() { writeDocumentations(); } + if (_loadingScreen && _assetManager->isDone()) { + _loadingScreen = nullptr; + } + _renderEngine->updateScene(); _renderEngine->updateFade(); _renderEngine->updateRenderer(); @@ -1177,6 +1181,13 @@ void OpenSpaceEngine::render(const glm::mat4& sceneMatrix, const glm::mat4& projectionMatrix) { LTRACE("OpenSpaceEngine::render(begin)"); + OnExit([] { + LTRACE("OpenSpaceEngine::render(end)"); + }); + + if (_loadingScreen) { + return; + } const bool isGuiWindow = _windowWrapper->hasGuiWindow() ? _windowWrapper->isGuiWindow() : true; @@ -1190,11 +1201,19 @@ void OpenSpaceEngine::render(const glm::mat4& sceneMatrix, func(); } - LTRACE("OpenSpaceEngine::render(end)"); + } void OpenSpaceEngine::drawOverlays() { LTRACE("OpenSpaceEngine::drawOverlays(begin)"); + OnExit([] { + LTRACE("OpenSpaceEngine::drawOverlays(end)"); + }); + if (_loadingScreen) { + _loadingScreen->render(); + return; + } + const bool isGuiWindow = _windowWrapper->hasGuiWindow() ? _windowWrapper->isGuiWindow() : true; @@ -1213,8 +1232,6 @@ void OpenSpaceEngine::drawOverlays() { for (const auto& func : _moduleCallbacks.draw2D) { func(); } - - LTRACE("OpenSpaceEngine::drawOverlays(end)"); } void OpenSpaceEngine::postDraw() { diff --git a/src/rendering/loadingscreen.cpp b/src/rendering/loadingscreen.cpp index b2cfd13c40..a9e505066f 100644 --- a/src/rendering/loadingscreen.cpp +++ b/src/rendering/loadingscreen.cpp @@ -71,8 +71,6 @@ namespace { const std::chrono::milliseconds TTL(5000); - const std::chrono::milliseconds RefreshRate(16); - bool rectOverlaps(glm::vec2 lhsLl, glm::vec2 lhsUr, glm::vec2 rhsLl, glm::vec2 rhsUr) { lhsLl -= glm::vec2(ItemStandoffDistance / 2.f); @@ -615,9 +613,6 @@ void LoadingScreen::render() { glEnable(GL_CULL_FACE); glEnable(GL_DEPTH_TEST); - - std::this_thread::sleep_for(RefreshRate); - OsEng.windowWrapper().swapBuffer(); } void LoadingScreen::postMessage(std::string message) { diff --git a/src/scene/assetmanager.cpp b/src/scene/assetmanager.cpp index dd0822f235..08fa74d597 100644 --- a/src/scene/assetmanager.cpp +++ b/src/scene/assetmanager.cpp @@ -185,6 +185,10 @@ scripting::LuaLibrary AssetManager::luaLibrary() { }; } +bool AssetManager::isDone() { + return _stateChangesInProgress.size() == 0; +} + std::shared_ptr AssetManager::tryLoadAsset(const std::string& path) { try { return _assetLoader->loadAsset(path); diff --git a/src/util/httprequest.cpp b/src/util/httprequest.cpp index 6fb8d00197..9239b037f5 100644 --- a/src/util/httprequest.cpp +++ b/src/util/httprequest.cpp @@ -53,6 +53,33 @@ namespace { } namespace openspace { + +namespace curlfunctions { +int progressCallback( + void* userData, + int64_t nTotalBytes, + int64_t nDownloadedBytes, + int64_t, + int64_t) +{ + HttpRequest* r = reinterpret_cast(userData); + return r->_onProgress( + HttpRequest::Progress{ + true, + static_cast(nTotalBytes), + static_cast(nDownloadedBytes) + } + ); + + LINFO("Transfer info from curl: " << nDownloadedBytes << " out of " << nTotalBytes); + return 0; +} + +size_t writeCallback(char* ptr, size_t size, size_t nmemb, void* userData) { + HttpRequest* r = reinterpret_cast(userData); + return r->_onData(HttpRequest::Data{ptr, size * nmemb}); +} +} HttpRequest::HttpRequest(std::string url) : _url(std::move(url)) @@ -103,86 +130,142 @@ void HttpRequest::perform(RequestOptions opt) { void HttpRequest::setReadyState(openspace::HttpRequest::ReadyState state) { _readyState = state; } - - -namespace curlfunctions { -int progressCallback(void* userData, - int64_t nTotalBytes, - int64_t nDownloadedBytes, - int64_t, - int64_t) -{ - HttpRequest* r = reinterpret_cast(userData); - return r->_onProgress( - HttpRequest::Progress{ - true, - static_cast(nTotalBytes), - static_cast(nDownloadedBytes) - } - ); - - LINFO("Transfer info from curl: " << nDownloadedBytes << " out of " << nTotalBytes); - return 0; -} -size_t writeCallback(char* ptr, size_t size, size_t nmemb, void* userData) { - HttpRequest* r = reinterpret_cast(userData); - return r->_onData(HttpRequest::Data{ptr, size * nmemb}); -} -} - - -using namespace openspace; - -HttpMemoryDownload::HttpMemoryDownload(std::string url) - : _httpRequest(url) +SyncHttpDownload::SyncHttpDownload(std::string url) + : _httpRequest(std::move(url)) {} -void HttpMemoryDownload::download(HttpRequest::RequestOptions opt) { - _httpRequest.onData([this](HttpRequest::Data d) { - _downloadedData.insert(_downloadedData.end(), d.buffer, d.buffer + d.size); - return d.size; +void SyncHttpDownload::download(HttpRequest::RequestOptions opt) { + initDownload(); + _httpRequest.onData([this] (HttpRequest::Data d) { + return handleData(d); }); _httpRequest.perform(opt); + deinitDownload(); } - + +AsyncHttpDownload::AsyncHttpDownload(std::string url) + : _httpRequest(std::move(url)) +{} + +void AsyncHttpDownload::start(HttpRequest::RequestOptions opt) { + std::lock_guard guard(_mutex); + if (_started) { + return; + } + _downloadThread = std::thread([this, opt] { + download(opt); + }); + _started = true; +} + +void AsyncHttpDownload::cancel() { + std::lock_guard guard(_mutex); + _shouldCancel = true; +} + +void AsyncHttpDownload::wait() { + std::unique_lock lock(_mutex); + _downloadFinishCondition.wait(lock, [this] { + return _finished; + }); +} + +void AsyncHttpDownload::download(HttpRequest::RequestOptions opt) { + std::unique_lock lock(_mutex); + + initDownload(); + + _httpRequest.onData([this](HttpRequest::Data d) { + std::lock_guard guard(_mutex); + return handleData(d); + }); + + _httpRequest.onProgress([this](HttpRequest::Progress p) { + std::lock_guard guard(_mutex); + if (_shouldCancel) { + return 1; + } + if (p.totalBytesKnown && p.downloadedBytes == p.totalBytes) { + _successful = true; + } + return 0; + }); + + lock.release(); + _httpRequest.perform(opt); + _finished = true; + _downloadFinishCondition.notify_all(); + + lock.lock(); + deinitDownload(); +} + const std::vector& HttpMemoryDownload::downloadedData() { return _downloadedData; } -HttpFileDownload::HttpFileDownload(std::string url, std::string destinationPath) - : _httpRequest(url) - , _destination(destinationPath) -{} - -void HttpFileDownload::download(HttpRequest::RequestOptions opt) { - LINFO(_destination); - - if (FileSys.fileExists(_destination)) { - LERROR("File already exists!"); - return; - } - - { - ghoul::filesystem::File f = _destination; - ghoul::filesystem::Directory d = f.directoryName(); - if (!FileSys.directoryExists(d)) { - FileSys.createDirectory(d, ghoul::filesystem::Directory::Recursive::Yes); - } - } - - std::ofstream f(_destination, std::ofstream::binary); - - if (f.fail()) { - LERROR("Cannot open file!"); - return; - } - _httpRequest.onData([this, &f](HttpRequest::Data d) { - f.write(d.buffer, d.size); - return d.size; - }); - _httpRequest.perform(opt); - f.close(); +bool HttpMemoryDownload::initDownload() { + return true; +} +bool HttpMemoryDownload::deinitDownload() { + return true; +} +size_t HttpMemoryDownload::handleData(HttpRequest::Data d) { + _downloadedData.insert(_downloadedData.end(), d.buffer, d.buffer + d.size); + return d.size; } +HttpFileDownload::HttpFileDownload(std::string destination) { + _destination = std::move(destination); +} + +bool HttpFileDownload::initDownload() { + if (FileSys.fileExists(_destination)) { + LERROR("File " << _destination << " already exists!"); + return false; + } + + ghoul::filesystem::File destinationFile = _destination; + ghoul::filesystem::Directory d = destinationFile.directoryName(); + if (!FileSys.directoryExists(d)) { + FileSys.createDirectory(d, ghoul::filesystem::Directory::Recursive::Yes); + } + + _file = std::ofstream(_destination, std::ofstream::binary); + + if (_file.fail()) { + LERROR("Cannot open file " << destinationFile); + return false; + } +} + +bool HttpFileDownload::deinitDownload() { + _file.close(); + return _file.good(); +} + +size_t HttpFileDownload::handleData(HttpRequest::Data d) { + _file.write(d.buffer, d.size); + return d.size; +} + +SyncHttpMemoryDownload::SyncHttpMemoryDownload(std::string url) + : SyncHttpDownload(std::move(url)) +{} + +SyncHttpFileDownload::SyncHttpFileDownload(std::string url, std::string destinationPath) + : SyncHttpDownload(std::move(url)) + , HttpFileDownload(std::move(destinationPath)) +{} + +AsyncHttpMemoryDownload::AsyncHttpMemoryDownload(std::string url) + : AsyncHttpDownload(std::move(url)) +{} + +AsyncHttpFileDownload::AsyncHttpFileDownload(std::string url, std::string destinationPath) + : AsyncHttpDownload(std::move(url)) + , HttpFileDownload(std::move(destinationPath)) +{} + } // namespace openspace