mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-01-26 05:58:58 -06:00
Merge branch 'develop' into feature/remote
* develop: (72 commits) Disable blackout on startup Fixed path bug Remove the rendering method override Fix crash that happens when SpiceManager is deinitialized Adding convenient scripts for showing 67P and changing coordinate system to 67P Adding hybrid read method for Pluto Cleanups + logical changes to parsing and sequencing Adding the possibility to project to arbitrary bodies model files Adding support for imageplanes for multiple instruments Fixing bug in model magnification Made destination optional in data specifications Renamed OpenSpaceModule's initialize method to create Created new initialize method that gets called in OpenSpaceEngine initialize Remove setName function from OpenSpaceModule and move naming into constructor Always build libtorrent as a static library Set Launcher as default application Don't copy curl.dll on non-windows system Correct CURL cmake specification Add the FindCurl module from CMake into the support directory Fix method renaming error in volume module Updated data folder reference Make SpiceManager derive from Singleton Allow left-aligned and right-aligned messages in Launcher ... Conflicts: modules/kameleon/CMakeLists.txt openspace.cfg src/engine/openspaceengine.cpp
This commit is contained in:
@@ -57,7 +57,9 @@ const std::string ConfigurationManager::KeySpiceLeapsecondKernel = "SpiceKernel.
|
||||
const std::string ConfigurationManager::KeyLogLevel = "Logging.LogLevel";
|
||||
const std::string ConfigurationManager::KeyLogImmediateFlush = "Logging.ImmediateFlush";
|
||||
const std::string ConfigurationManager::KeyLogs = "Logging.Logs";
|
||||
const std::string ConfigurationManager::KeyCapabilitiesVerbosity = "Logging.CapabilitiesVerbosity";
|
||||
const std::string ConfigurationManager::KeyDisableMasterRendering = "DisableRenderingOnMaster";
|
||||
const std::string ConfigurationManager::KeyDownloadRequestURL = "DownloadRequestURL";
|
||||
|
||||
bool ConfigurationManager::loadFromFile(const std::string& filename) {
|
||||
using ghoul::filesystem::FileSystem;
|
||||
|
||||
278
src/engine/downloadmanager.cpp
Normal file
278
src/engine/downloadmanager.cpp
Normal file
@@ -0,0 +1,278 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2015 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <openspace/engine/downloadmanager.h>
|
||||
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <ghoul/misc/assert.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <fstream>
|
||||
#include <thread>
|
||||
|
||||
#ifdef OPENSPACE_CURL_ENABLED
|
||||
#include <curl/curl.h>
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
const std::string _loggerCat = "DownloadManager";
|
||||
|
||||
const std::string RequestIdentifier = "identifier";
|
||||
const std::string RequestFileVersion = "file_version";
|
||||
const std::string RequestApplicationVersion = "application_version";
|
||||
|
||||
struct ProgressInformation {
|
||||
openspace::DownloadManager::FileFuture* future;
|
||||
std::chrono::system_clock::time_point startTime;
|
||||
const openspace::DownloadManager::DownloadProgressCallback* callback;
|
||||
};
|
||||
|
||||
size_t writeData(void* ptr, size_t size, size_t nmemb, FILE* stream) {
|
||||
size_t written;
|
||||
written = fwrite(ptr, size, nmemb, stream);
|
||||
return written;
|
||||
}
|
||||
|
||||
|
||||
int xferinfo(void* p,
|
||||
curl_off_t dltotal, curl_off_t dlnow,
|
||||
curl_off_t ultotal, curl_off_t ulnow)
|
||||
{
|
||||
if (dltotal == 0)
|
||||
return 0;
|
||||
|
||||
ghoul_assert(p, "Passed progress information is nullptr");
|
||||
ProgressInformation* i = static_cast<ProgressInformation*>(p);
|
||||
ghoul_assert(i, "Passed pointer is not a ProgressInformation");
|
||||
ghoul_assert(i->future, "FileFuture is not initialized");
|
||||
ghoul_assert(i->callback, "Callback pointer is nullptr");
|
||||
|
||||
if (i->future->abortDownload) {
|
||||
i->future->isAborted = true;
|
||||
return 1;
|
||||
}
|
||||
|
||||
i->future->currentSize = dlnow;
|
||||
i->future->totalSize = dltotal;
|
||||
i->future->progress = static_cast<float>(dlnow) / static_cast<float>(dltotal);
|
||||
|
||||
auto now = std::chrono::system_clock::now();
|
||||
|
||||
// Compute time spent transferring.
|
||||
auto transferTime = now - i->startTime;
|
||||
// Compute estimated transfer time.
|
||||
auto estimatedTime = transferTime / i->future->progress;
|
||||
// Compute estimated time remaining.
|
||||
auto timeRemaining = estimatedTime - transferTime;
|
||||
|
||||
float s = std::chrono::duration_cast<std::chrono::seconds>(timeRemaining).count();
|
||||
|
||||
i->future->secondsRemaining = s;
|
||||
|
||||
if (*(i->callback)) {
|
||||
// The callback function is a pointer to an std::function; that is the reason
|
||||
// for the excessive referencing
|
||||
(*(i->callback))(*(i->future));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
namespace openspace {
|
||||
|
||||
DownloadManager::FileFuture::FileFuture(std::string file)
|
||||
: currentSize(-1)
|
||||
, totalSize(-1)
|
||||
, progress(0.f)
|
||||
, secondsRemaining(-1.f)
|
||||
, isFinished(false)
|
||||
, isAborted(false)
|
||||
, filePath(std::move(file))
|
||||
, errorMessage("")
|
||||
, abortDownload(false)
|
||||
{}
|
||||
|
||||
DownloadManager::DownloadManager(std::string requestURL, int applicationVersion)
|
||||
: _requestURL(std::move(requestURL))
|
||||
, _applicationVersion(std::move(applicationVersion))
|
||||
{
|
||||
curl_global_init(CURL_GLOBAL_ALL);
|
||||
// TODO: Check if URL is accessible ---abock
|
||||
// TODO: Allow for multiple requestURLs
|
||||
}
|
||||
|
||||
DownloadManager::FileFuture* DownloadManager::downloadFile(
|
||||
const std::string& url,
|
||||
const ghoul::filesystem::File& file,
|
||||
bool overrideFile,
|
||||
DownloadFinishedCallback finishedCallback,
|
||||
DownloadProgressCallback progressCallback)
|
||||
{
|
||||
if (!overrideFile && FileSys.fileExists(file))
|
||||
return nullptr;
|
||||
|
||||
FileFuture* future = new FileFuture(
|
||||
file.filename()
|
||||
);
|
||||
FILE* fp = fopen(file.path().c_str(), "wb");
|
||||
|
||||
LDEBUG("Starting download for file: '" << url <<
|
||||
"' into file '" << file.path() << "'");
|
||||
std::thread t = std::thread([url, finishedCallback, progressCallback, future, fp]() {
|
||||
CURL* curl = curl_easy_init();
|
||||
if (curl) {
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeData);
|
||||
|
||||
ProgressInformation p = {
|
||||
future,
|
||||
std::chrono::system_clock::now(),
|
||||
&progressCallback
|
||||
};
|
||||
curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, xferinfo);
|
||||
curl_easy_setopt(curl, CURLOPT_XFERINFODATA, &p);
|
||||
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
|
||||
|
||||
CURLcode res = curl_easy_perform(curl);
|
||||
curl_easy_cleanup(curl);
|
||||
fclose(fp);
|
||||
|
||||
if (res == CURLE_OK)
|
||||
future->isFinished = true;
|
||||
else
|
||||
future->errorMessage = curl_easy_strerror(res);
|
||||
|
||||
if (finishedCallback)
|
||||
finishedCallback(*future);
|
||||
}
|
||||
});
|
||||
|
||||
#ifdef WIN32
|
||||
std::thread::native_handle_type h = t.native_handle();
|
||||
SetPriorityClass(h, IDLE_PRIORITY_CLASS);
|
||||
SetThreadPriority(h, THREAD_PRIORITY_LOWEST);
|
||||
#else
|
||||
// TODO: Implement thread priority ---abock
|
||||
#endif
|
||||
|
||||
t.detach();
|
||||
|
||||
return future;
|
||||
}
|
||||
|
||||
std::vector<DownloadManager::FileFuture*> DownloadManager::downloadRequestFiles(
|
||||
const std::string& identifier,
|
||||
const ghoul::filesystem::Directory& destination,
|
||||
int version,
|
||||
bool overrideFiles,
|
||||
DownloadFinishedCallback finishedCallback,
|
||||
DownloadProgressCallback progressCallback)
|
||||
{
|
||||
std::vector<FileFuture*> futures;
|
||||
bool s = FileSys.createDirectory(destination, true);
|
||||
// TODO: Check s ---abock
|
||||
// TODO: Escaping is necessary ---abock
|
||||
const std::string fullRequest =_requestURL + "?" +
|
||||
RequestIdentifier + "=" + identifier + "&" +
|
||||
RequestFileVersion + "=" + std::to_string(version) + "&" +
|
||||
RequestApplicationVersion + "=" + std::to_string(_applicationVersion);
|
||||
LDEBUG("Request: " << fullRequest);
|
||||
|
||||
std::string requestFile = absPath("${TEMPORARY}/" + identifier);
|
||||
LDEBUG("Request File: " << requestFile);
|
||||
|
||||
bool isFinished = false;
|
||||
auto callback = [&futures, destination, &progressCallback, &isFinished, requestFile, overrideFiles](const FileFuture& f) {
|
||||
LDEBUG("Finished: " << requestFile);
|
||||
std::ifstream temporary(requestFile);
|
||||
std::string line;
|
||||
int nFiles = 0;
|
||||
int nFinished = 0;
|
||||
while (std::getline(temporary, line)) {
|
||||
++nFiles;
|
||||
std::string file = ghoul::filesystem::File(line).filename();
|
||||
|
||||
LDEBUG("\tLine: " << line << " ; Dest: " << destination.path() + "/" + file);
|
||||
|
||||
FileFuture* future = DlManager.downloadFile(
|
||||
line,
|
||||
destination.path() + "/" + file,
|
||||
overrideFiles
|
||||
);
|
||||
if (future)
|
||||
futures.push_back(future);
|
||||
}
|
||||
isFinished = true;
|
||||
};
|
||||
|
||||
FileFuture* f = downloadFile(
|
||||
fullRequest,
|
||||
requestFile,
|
||||
true,
|
||||
callback
|
||||
);
|
||||
|
||||
while (!isFinished) {}
|
||||
|
||||
return futures;
|
||||
}
|
||||
|
||||
void DownloadManager::downloadRequestFilesAsync(
|
||||
const std::string& identifier,
|
||||
const ghoul::filesystem::Directory& destination,
|
||||
int version,
|
||||
bool overrideFiles,
|
||||
AsyncDownloadFinishedCallback callback)
|
||||
{
|
||||
std::thread t = std::thread([this, identifier, destination, version, overrideFiles, callback](){
|
||||
std::vector<FileFuture*> f = downloadRequestFiles(
|
||||
identifier,
|
||||
destination,
|
||||
version,
|
||||
overrideFiles
|
||||
);
|
||||
|
||||
callback(f);
|
||||
});
|
||||
|
||||
#ifdef WIN32
|
||||
std::thread::native_handle_type h = t.native_handle();
|
||||
SetPriorityClass(h, IDLE_PRIORITY_CLASS);
|
||||
SetThreadPriority(h, THREAD_PRIORITY_LOWEST);
|
||||
#else
|
||||
// TODO: Implement thread priority ---abock
|
||||
#endif
|
||||
|
||||
t.detach();
|
||||
}
|
||||
|
||||
} // namespace openspace
|
||||
@@ -36,11 +36,39 @@ namespace {
|
||||
|
||||
namespace openspace {
|
||||
|
||||
bool ModuleEngine::initialize() {
|
||||
LDEBUG("Initializing modules");
|
||||
bool ModuleEngine::create() {
|
||||
LDEBUG("Creating modules");
|
||||
|
||||
registerModules(AllModules);
|
||||
|
||||
for (OpenSpaceModule* m : _modules) {
|
||||
bool success = m->create();
|
||||
if (!success) {
|
||||
LERROR("Could not initialize module '" << m->name() << "'");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
LDEBUG("Finished creating modules");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ModuleEngine::destroy() {
|
||||
LDEBUG("Destroying modules");
|
||||
for (OpenSpaceModule* m : _modules) {
|
||||
bool success = m->destroy();
|
||||
if (!success) {
|
||||
LERROR("Could not deinitialize module '" << m->name() << "'");
|
||||
return false;
|
||||
}
|
||||
delete m;
|
||||
}
|
||||
LDEBUG("Finished destroying modules");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ModuleEngine::initialize() {
|
||||
LDEBUG("Initializing modules");
|
||||
|
||||
for (OpenSpaceModule* m : _modules) {
|
||||
bool success = m->initialize();
|
||||
if (!success) {
|
||||
@@ -54,13 +82,13 @@ bool ModuleEngine::initialize() {
|
||||
|
||||
bool ModuleEngine::deinitialize() {
|
||||
LDEBUG("Deinitializing modules");
|
||||
|
||||
for (OpenSpaceModule* m : _modules) {
|
||||
bool success = m->deinitialize();
|
||||
if (!success) {
|
||||
LERROR("Could not deinitialize module '" << m->name() << "'");
|
||||
return false;
|
||||
}
|
||||
delete m;
|
||||
}
|
||||
LDEBUG("Finished Deinitializing modules");
|
||||
return true;
|
||||
@@ -78,5 +106,4 @@ const std::vector<OpenSpaceModule*> ModuleEngine::modules() const {
|
||||
return _modules;
|
||||
}
|
||||
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
#include <openspace/util/spicemanager.h>
|
||||
#include <openspace/util/syncbuffer.h>
|
||||
#include <openspace/engine/moduleengine.h>
|
||||
#include <openspace/network/parallelconnection.h>
|
||||
#include <openspace/engine/downloadmanager.h>
|
||||
|
||||
#include <ghoul/ghoul.h>
|
||||
#include <ghoul/cmdparser/commandlineparser.h>
|
||||
@@ -73,7 +73,6 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
using namespace openspace::scripting;
|
||||
using namespace ghoul::filesystem;
|
||||
using namespace ghoul::logging;
|
||||
@@ -88,6 +87,7 @@ namespace {
|
||||
const std::string _sgctConfigArgumentCommand = "-config";
|
||||
|
||||
const int CacheVersion = 1;
|
||||
const int DownloadVersion = 1;
|
||||
|
||||
struct {
|
||||
std::string configurationName;
|
||||
@@ -233,7 +233,7 @@ bool OpenSpaceEngine::create(
|
||||
}
|
||||
|
||||
// Register modules
|
||||
_engine->_moduleEngine->initialize();
|
||||
_engine->_moduleEngine->create();
|
||||
|
||||
// Create the cachemanager
|
||||
FileSys.createCacheManager(absPath("${" + ConfigurationManager::KeyCache + "}"), CacheVersion);
|
||||
@@ -267,6 +267,7 @@ bool OpenSpaceEngine::create(
|
||||
|
||||
void OpenSpaceEngine::destroy() {
|
||||
_engine->_moduleEngine->deinitialize();
|
||||
_engine->_moduleEngine->destroy();
|
||||
_engine->_console->deinitialize();
|
||||
|
||||
_engine->_scriptEngine->deinitialize();
|
||||
@@ -291,10 +292,29 @@ bool OpenSpaceEngine::initialize() {
|
||||
SysCap.addComponent(new ghoul::systemcapabilities::GeneralCapabilitiesComponent);
|
||||
SysCap.addComponent(new ghoul::systemcapabilities::OpenGLCapabilitiesComponent);
|
||||
SysCap.detectCapabilities();
|
||||
SysCap.logCapabilities();
|
||||
|
||||
using Verbosity = ghoul::systemcapabilities::SystemCapabilitiesComponent::Verbosity;
|
||||
Verbosity verbosity = Verbosity::Default;
|
||||
if (configurationManager()->hasKeyAndValue<std::string>(ConfigurationManager::KeyCapabilitiesVerbosity)) {
|
||||
std::map<std::string, Verbosity> verbosityMap = {
|
||||
{ "Minimal", Verbosity::Minimal },
|
||||
{ "Default", Verbosity::Default },
|
||||
{ "Full", Verbosity::Full }
|
||||
};
|
||||
|
||||
std::string v = configurationManager()->value<std::string>(ConfigurationManager::KeyCapabilitiesVerbosity);
|
||||
if (verbosityMap.find(v) != verbosityMap.end())
|
||||
verbosity = verbosityMap[v];
|
||||
}
|
||||
SysCap.logCapabilities(verbosity);
|
||||
|
||||
std::string requestURL = "";
|
||||
bool success = configurationManager()->getValue(ConfigurationManager::KeyDownloadRequestURL, requestURL);
|
||||
if (success)
|
||||
DownloadManager::initialize(requestURL, DownloadVersion);
|
||||
|
||||
// Load SPICE time kernel
|
||||
bool success = loadSpiceKernels();
|
||||
success = loadSpiceKernels();
|
||||
if (!success)
|
||||
return false;
|
||||
|
||||
@@ -336,11 +356,6 @@ bool OpenSpaceEngine::initialize() {
|
||||
|
||||
// initialize the RenderEngine
|
||||
_renderEngine->initialize();
|
||||
// if (_configurationManager->hasKeyAndValue<std::string>(KeyRenderingMethod))
|
||||
// _renderEngine->initialize(_configurationManager->value<std::string>(KeyRenderingMethod));
|
||||
// else
|
||||
// _renderEngine->initialize(DefaultRenderingMethod);
|
||||
|
||||
sceneGraph->initialize();
|
||||
|
||||
std::string sceneDescriptionPath;
|
||||
@@ -350,8 +365,6 @@ bool OpenSpaceEngine::initialize() {
|
||||
sceneGraph->scheduleLoadSceneFile(sceneDescriptionPath);
|
||||
|
||||
_interactionHandler->setKeyboardController(new interaction::KeyboardControllerFixed);
|
||||
//_interactionHandler.setKeyboardController(new interaction::KeyboardControllerLua);
|
||||
//_interactionHandler.setMouseController(new interaction::TrackballMouseController);
|
||||
_interactionHandler->setMouseController(new interaction::OrbitalMouseController);
|
||||
|
||||
// Run start up scripts
|
||||
@@ -363,6 +376,8 @@ bool OpenSpaceEngine::initialize() {
|
||||
LINFO("Initializing GUI");
|
||||
_gui->initialize();
|
||||
|
||||
// Initialize modules
|
||||
_moduleEngine->initialize();
|
||||
|
||||
LINFO("Finished initializing");
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user