Code formatting to match style guide

This commit is contained in:
Emil Axelsson
2019-09-20 16:42:01 +02:00
parent 121216b8d9
commit 675548366e
4 changed files with 1653 additions and 1513 deletions

View File

@@ -34,169 +34,185 @@
namespace {
constexpr const char* _loggerCat = "FieldlinesSequence[ Web FLs Manager ]";
constexpr const char* _loggerCat = "WebFieldlinesManager";
} // namepace
namespace openspace{
// --------------------------- PUBLIC FUNCTIONS --------------------------- //
void WebFieldlinesManager::initializeWebFieldlinesManager(std::string identifier, std::string url, size_t& _nStates, std::vector<std::string>& _sourceFiles,
std::vector<double>& _startTimes)
// --------------------------- PUBLIC FUNCTIONS --------------------------- //
void WebFieldlinesManager::initializeWebFieldlinesManager(std::string identifier,
std::string url,
size_t& _nStates,
std::vector<std::string>& _sourceFiles,
std::vector<double>& _startTimes)
{
// Initialize the sliding window
_webFieldlinesWindow =
WebFieldlinesWindow(_syncDir, url, _sourceFiles, _startTimes, _nStates);
LTRACE("WebFieldlinesManager initialized " + identifier);
}
bool WebFieldlinesManager::isConnected() {
return _connected;
}
// Make sure that the sync directory exists
// Also creates a new directory in the web_fieldlines directory corresponding to the
// field line identifier
std::string WebFieldlinesManager::initializeSyncDirectory(std::string identifier) {
std::string path =
absPath("${BASE}/sync/http/web_fieldlines") + FileSys.PathSeparator;
if (!FileSys.directoryExists(path)) {
FileSys.createDirectory(path);
}
path = absPath(path + identifier);
if(!FileSys.directoryExists(path)) {
FileSys.createDirectory(path);
}
_syncDir = path;
return _syncDir;
}
// Temporary function - this should be moved to the worker. It's to download
// the start latest line
// this could be used to test the connection too
void WebFieldlinesManager::preDownload(std::string dUrl){
int ID = std::stoi(dUrl.substr(dUrl.size() - 4));
std::string type = "";
switch (ID)
{
// Initialize the sliding window
_webFieldlinesWindow = WebFieldlinesWindow(_syncDir, url, _sourceFiles, _startTimes, _nStates);
case 1176:
type = "trace_sun_earth";
break;
case 1177:
type = "trace_scs_outtoin";
break;
case 1178:
type = "trace_pfss_intoout";
break;
case 1179:
type = "trace_pfss_outtoin";
break;
case 1180:
type = "WSA_OUT";
break;
LTRACE("WebFieldlinesManager initialized " + identifier);
// Parker solar probe endpoints
case 1192:
type = "trace_sub_psp";
break;
case 1193:
type = "trace_scs_outtoin";
break;
case 1194:
type = "trace_pfss_intoout";
break;
case 1195:
type = "trace_pfss_outtoin";
break;
case 1196:
type = "ADAPT_WSA_OUT";
break;
}
bool WebFieldlinesManager::isConnected() {
return _connected;
}
// Make sure that the sync directory exists
// Also creates a new directory in the web_fieldlines directory corresponding to the field line identifier
std::string WebFieldlinesManager::initializeSyncDirectory(std::string identifier) {
std::string path = absPath("${BASE}/sync/http/web_fieldlines") + FileSys.PathSeparator;
if (!FileSys.directoryExists(path)) {
FileSys.createDirectory(path);
}
path = absPath(path + identifier);
if(!FileSys.directoryExists(path)) {
FileSys.createDirectory(path);
}
_syncDir = path;
return _syncDir;
}
// Temporary function - this should be moved to the worker. It's to download
// the start latest line
// this could be used to test the connection too
void WebFieldlinesManager::preDownload(std::string dUrl){
int ID = std::stoi(dUrl.substr(dUrl.size() - 4));
std::string type = "";
switch (ID)
{
case 1176:
type = "trace_sun_earth";
break;
case 1177:
type = "trace_scs_outtoin";
break;
case 1178:
type = "trace_pfss_intoout";
break;
case 1179:
type = "trace_pfss_outtoin";
break;
case 1180:
type = "WSA_OUT";
break;
// Parker solar probe endpoints
case 1192:
type = "trace_sub_psp";
break;
case 1193:
type = "trace_scs_outtoin";
break;
case 1194:
type = "trace_pfss_intoout";
break;
case 1195:
type = "trace_pfss_outtoin";
break;
case 1196:
type = "ADAPT_WSA_OUT";
break;
}
// TODO(Axel): Change this endpoint to be dynamic for each dataset
std::string url = "https://iswa.ccmc.gsfc.nasa.gov/iswa_data_tree/model/solar/WSA4.5/WSA4.5_fieldlines/" + type + "/2017/09/2017-09-28T00-23-22.000.osfls";
std::string destinationpath = absPath(_syncDir + ghoul::filesystem::FileSystem::PathSeparator + "2017-09-28T00-23-22.000.osfls"); // what the downloaded filename is to be
// TODO(Axel): Change this endpoint to be dynamic for each dataset
std::string url = "https://iswa.ccmc.gsfc.nasa.gov/iswa_data_tree/model/solar/WSA4.5/WSA4.5_fieldlines/" + type + "/2017/09/2017-09-28T00-23-22.000.osfls";
std::string destinationpath = absPath(_syncDir + ghoul::filesystem::FileSystem::PathSeparator + "2017-09-28T00-23-22.000.osfls"); // what the downloaded filename is to be
/* For experimentation with suntexturemanager & parker solor probe, hopefully this hardcoding can go away */
if (ID == 1180) {
url = "https://iswa.ccmc.gsfc.nasa.gov/iswa_data_tree/model/solar/WSA4.5/" + type + "/2017/09/wsa_201709280023R000_gong.fits";
destinationpath = absPath(_syncDir + ghoul::filesystem::FileSystem::PathSeparator + "wsa_201709280023R000_gong.fits"); // what the downloaded filename is to be
}
// For parker solar probe
if (ID > 1190) {
url = "https://iswa.ccmc.gsfc.nasa.gov/iswa_data_tree/model/solar/ADAPT_WSA4.5/ADAPT_WSA4.5_fieldlines/" + type + "/2018/11/2018-11-01T00-00-00.000.osfls";
destinationpath = absPath(_syncDir + ghoul::filesystem::FileSystem::PathSeparator + "2018-11-01T00-00-00.000.osfls"); // what the downloaded filename is to be
}
if (ID == 1196) {
url = "https://iswa.ccmc.gsfc.nasa.gov/iswa_data_tree/model/solar/ADAPT_WSA4.5/" + type + "/2018/11/wsa_201811010000R007_agong.fits";
destinationpath = absPath(_syncDir + ghoul::filesystem::FileSystem::PathSeparator + "wsa_201811010000R007_agong.fits"); // what the downloaded filename is to be
}
/* End of experiment */
AsyncHttpFileDownload ashd = AsyncHttpFileDownload(url, destinationpath, HttpFileDownload::Overwrite::Yes);
HttpRequest::RequestOptions opt = {};
opt.requestTimeoutSeconds = 0;
ashd.start(opt);
ashd.wait();
/* For experimentation with suntexturemanager & parker solor probe, hopefully this hardcoding can go away */
if (ID == 1180) {
url = "https://iswa.ccmc.gsfc.nasa.gov/iswa_data_tree/model/solar/WSA4.5/" + type + "/2017/09/wsa_201709280023R000_gong.fits";
destinationpath = absPath(_syncDir + ghoul::filesystem::FileSystem::PathSeparator + "wsa_201709280023R000_gong.fits"); // what the downloaded filename is to be
}
// For parker solar probe
if (ID > 1190) {
url = "https://iswa.ccmc.gsfc.nasa.gov/iswa_data_tree/model/solar/ADAPT_WSA4.5/ADAPT_WSA4.5_fieldlines/" + type + "/2018/11/2018-11-01T00-00-00.000.osfls";
destinationpath = absPath(_syncDir + ghoul::filesystem::FileSystem::PathSeparator + "2018-11-01T00-00-00.000.osfls"); // what the downloaded filename is to be
}
if (ID == 1196) {
url = "https://iswa.ccmc.gsfc.nasa.gov/iswa_data_tree/model/solar/ADAPT_WSA4.5/" + type + "/2018/11/wsa_201811010000R007_agong.fits";
destinationpath = absPath(_syncDir + ghoul::filesystem::FileSystem::PathSeparator + "wsa_201811010000R007_agong.fits"); // what the downloaded filename is to be
}
/* End of experiment */
AsyncHttpFileDownload ashd = AsyncHttpFileDownload(url, destinationpath, HttpFileDownload::Overwrite::Yes);
HttpRequest::RequestOptions opt = {};
opt.requestTimeoutSeconds = 0;
ashd.start(opt);
ashd.wait();
}
void WebFieldlinesManager::update(){
const double openspaceTime = global::timeManager.time().j2000Seconds();
const auto deltaTime = global::timeManager.deltaTime();
const int speedThreshhold = 7200; // More than 2hrs a second would generally be unfeasable for a regular internet connection to operate at
void WebFieldlinesManager::update(){
const double openspaceTime = global::timeManager.time().j2000Seconds();
const auto deltaTime = global::timeManager.deltaTime();
// More than 2hrs a second would generally be unfeasable
// for a regular internet connection to operate at
const int speedThreshhold = 7200;
// Hold your horses, we don't want to do anything while deltatime is too high
if (abs(deltaTime) < speedThreshhold){
// First it checks the time against the "bigger window" aka the long list of
// timesteps we know are available online. If it's outside that we're gonna need a new one
if (_webFieldlinesWindow.timeIsInTriggerTimesWebList(openspaceTime) && !_webFieldlinesWindow.expectedWindowIsOutOfBounds(openspaceTime) || _webFieldlinesWindow.checkWorkerEdgeMode()){
// Check if in window
if (_webFieldlinesWindow.edgeWindowReady() || _webFieldlinesWindow.timeIsInWindow(openspaceTime)) {
// Check if in the edge of the window, so we can start downloading a new one
if (!_webFieldlinesWindow.edgeWindowReady() && _webFieldlinesWindow.timeIsInWindowMargin(openspaceTime, deltaTime)) {
// get new window
_webFieldlinesWindow.newWindow(openspaceTime);
hasUpdated = false;
}
else {
// If it's in the middle of the window, we can just sit back and relax and let the worker work
_webFieldlinesWindow.executeDownloadWorker();
}
}
else {
// Hold your horses, we don't want to do anything while deltatime is too high
if (abs(deltaTime) < speedThreshhold) {
// First it checks the time against the "bigger window" aka the long list of
// timesteps we know are available online.
// If it's outside that we're gonna need a new one
if (_webFieldlinesWindow.timeIsInTriggerTimesWebList(openspaceTime) &&
!_webFieldlinesWindow.expectedWindowIsOutOfBounds(openspaceTime) ||
_webFieldlinesWindow.checkWorkerEdgeMode())
{
// Check if in window
if (_webFieldlinesWindow.edgeWindowReady() ||
_webFieldlinesWindow.timeIsInWindow(openspaceTime))
{
// Check if in the edge of the window,
// so we can start downloading a new one
if (!_webFieldlinesWindow.edgeWindowReady() &&
_webFieldlinesWindow.timeIsInWindowMargin(openspaceTime, deltaTime))
{
// get new window
_webFieldlinesWindow.newWindow(openspaceTime);
hasUpdated = false;
}
else {
// If it's in the middle of the window,
// we can just sit back and relax and let the worker work
_webFieldlinesWindow.executeDownloadWorker();
}
}
else {
_webFieldlinesWindow.getNewTriggerTimesWebList(openspaceTime);
// get new window
_webFieldlinesWindow.newWindow(openspaceTime);
hasUpdated = false;
}
}
}
else {
_webFieldlinesWindow.getNewTriggerTimesWebList(openspaceTime);
}
}
}
bool WebFieldlinesManager::checkIfWindowIsReadyToLoad()
{
return _webFieldlinesWindow.workerWindowIsReady();
}
bool WebFieldlinesManager::checkIfWindowIsReadyToLoad()
{
return _webFieldlinesWindow.workerWindowIsReady();
}
void WebFieldlinesManager::resetWorker() {
_webFieldlinesWindow.rfsHasUpdated();
}
void WebFieldlinesManager::resetWorker() {
_webFieldlinesWindow.rfsHasUpdated();
}
// --------------------------- PRIVATE FUNCTIONS --------------------------- //
// --------------------------- PRIVATE FUNCTIONS --------------------------- //
std::string WebFieldlinesManager::getDirectory(){
return _syncDir;
}
std::string WebFieldlinesManager::getDirectory(){
return _syncDir;
}
} // namespace openspace

View File

@@ -34,160 +34,176 @@
namespace {
constexpr const char* _loggerCat = "FieldlinesSequence[ Web FLs Window ]";
constexpr const char* _loggerCat = "WebFieldlinesWindow";
} // namespace
namespace openspace{
// --------------------------- CONSTRUCTORS ---------------------------------------//
WebFieldlinesWindow::WebFieldlinesWindow(std::string syncDir, std::string serverUrl,
std::vector<std::string>& _sourceFiles,
std::vector<double>& _startTimes, size_t& _nStates)
{
_window.backWidth = 3;
_window.forwardWidth = 3;
WebFieldlinesWindow::WebFieldlinesWindow(std::string syncDir, std::string serverUrl,
std::vector<std::string>& _sourceFiles,
std::vector<double>& _startTimes, size_t& _nStates)
{
_window.backWidth = 3;
_window.forwardWidth = 3;
_window.nTriggerTimes = static_cast<int>(_nStates);
_window.nTriggerTimes = static_cast<int>(_nStates);
for(int i = 0; i < _window.nTriggerTimes ; i++){
_window.triggerTimes.push_back(std::make_pair(_startTimes[i], _sourceFiles[i]));
}
rfs_nStates = &_nStates;
rfs_sourceFiles = &_sourceFiles;
rfs_startTimes = &_startTimes;
_nAvailableWeb = 0; // haven't downloaded that list yet
_worker = WebFieldlinesWorker(syncDir, serverUrl);
for(int i = 0; i < _window.nTriggerTimes ; i++){
_window.triggerTimes.push_back(
std::make_pair(_startTimes[i], _sourceFiles[i])
);
}
rfs_nStates = &_nStates;
rfs_sourceFiles = &_sourceFiles;
rfs_startTimes = &_startTimes;
_nAvailableWeb = 0; // haven't downloaded that list yet
_worker = WebFieldlinesWorker(syncDir, serverUrl);
}
// Returns true if time is inside the current window
bool WebFieldlinesWindow::timeIsInWindow(double time) {
return time >= windowStart() && time <= windowEnd();
}
// -------------------------- PUBLIC FUNCTIONS -----------------------------------//
// Returns true if time is inside the current window
bool WebFieldlinesWindow::timeIsInWindow(double time){
if(time >= windowStart() && time <= windowEnd())
// Returns true if time is at edge of the current window,
// and will probably need to update window
bool WebFieldlinesWindow::timeIsInWindowMargin(double time, double direction) {
const int threshold = 2; // base this on speed later
if (direction > 0){ // If time is moving forward
if (time >= _window.triggerTimes[_window.nTriggerTimes - threshold].first) {
if (time > windowEnd()) {
return false;
}
return true;
}
else return false;
}
// Returns true if time is at edge of the current window,
// and will probably need to update window
bool WebFieldlinesWindow::timeIsInWindowMargin(double time, double direction){
int threshold = 2; // base this on speed later
if (direction > 0){ // If time is moving forward
if(time >= _window.triggerTimes[_window.nTriggerTimes - threshold].first){
if(time > windowEnd()){
return false;
}
return true;
else{ // If time is moving backwards
if (time <= _window.triggerTimes[threshold].first){
if (time < windowStart()) {
return false;
}
else return false;
}
else{ // If time is moving backwards
if(time <= _window.triggerTimes[threshold].first){
if(time < windowStart()){
return false;
}
return true;
}
else return false;
}
}
/* Release the worker for execution,
Pick up a timestep to request for download,
Check if that timestep is already on disk,
repeated until a proper timestep to download is found, and start download */
void WebFieldlinesWindow::executeDownloadWorker(){
_worker.downloadWindow(_window.triggerTimes);
_worker.updateRFSSourceFiles(*rfs_sourceFiles);
_edgeWindowReady = false;
}
void WebFieldlinesWindow::newWindow(double time){
auto it = std::find_if(_triggerTimesWeb.rbegin(), _triggerTimesWeb.rend(), [time](auto element) {
return time > element.first;
});
const int index = static_cast<int>(std::distance(it, _triggerTimesWeb.rend())) - 1;
_window.triggerTimes.clear();
_window.nTriggerTimes = 0;
// This should be safe, because in the manager, it is checked wether the current position is within
// the boundaries with respect to back & forward width
for(int i = std::max(index - _window.backWidth,0); i <= std::min(index + _window.forwardWidth, static_cast<int>(_triggerTimesWeb.size() -1)); i++){
_window.triggerTimes.push_back(std::make_pair(_triggerTimesWeb[i].first, _triggerTimesWeb[i].second));
_window.nTriggerTimes++;
}
if (_worker.edgeMode())
_edgeWindowReady = true;
_worker.newWindowToDownload();
}
bool WebFieldlinesWindow::timeIsInTriggerTimesWebList(double time){
// There are no files to compare with, just going to be false.
if(_nAvailableWeb == 0) return false;
// Most cases, we are currently in the middle of a bunch of datasets, if we are not, lets get some new ones.
if(time >= (_triggerTimesWeb.front().first) && time <= (_triggerTimesWeb.back().first))
return true;
else
return false;
}
else return false;
}
}
/*
Release the worker for execution,
Pick up a timestep to request for download,
Check if that timestep is already on disk,
repeated until a proper timestep to download is found, and start download
*/
void WebFieldlinesWindow::executeDownloadWorker() {
_worker.downloadWindow(_window.triggerTimes);
_worker.updateRFSSourceFiles(*rfs_sourceFiles);
_edgeWindowReady = false;
}
void WebFieldlinesWindow::getNewTriggerTimesWebList(double time){
_worker.getRangeOfAvailableTriggerTimes(time, time, _triggerTimesWeb);
_nAvailableWeb = static_cast<int>(_triggerTimesWeb.size());
void WebFieldlinesWindow::newWindow(double time) {
auto it = std::find_if(
_triggerTimesWeb.rbegin(),
_triggerTimesWeb.rend(),
[time](auto element) {
return time > element.first;
}
);
const int index = static_cast<int>(std::distance(it, _triggerTimesWeb.rend())) - 1;
_window.triggerTimes.clear();
_window.nTriggerTimes = 0;
// This should be safe, because in the manager,
// it is checked wether the current position is within
// the boundaries with respect to back & forward width
for(int i = std::max(index - _window.backWidth,0);
i <= std::min(index + _window.forwardWidth,
static_cast<int>(_triggerTimesWeb.size() -1));
i++) {
_window.triggerTimes.push_back(
std::make_pair(_triggerTimesWeb[i].first, _triggerTimesWeb[i].second)
);
_window.nTriggerTimes++;
}
bool WebFieldlinesWindow::workerWindowIsReady()
{
return _worker.windowIsComplete();
if (_worker.edgeMode()) {
_edgeWindowReady = true;
}
bool WebFieldlinesWindow::expectedWindowIsOutOfBounds(double time) {
auto resultForwards = std::find_if(_triggerTimesWeb.rbegin(), _triggerTimesWeb.rbegin() + _window.forwardWidth, [time](auto pair) {
_worker.newWindowToDownload();
}
bool WebFieldlinesWindow::timeIsInTriggerTimesWebList(double time) {
// There are no files to compare with, just going to be false.
if (_nAvailableWeb == 0) return false;
// Most cases, we are currently in the middle of a bunch of datasets,
// if we are not, lets get some new ones.
return (
time >= (_triggerTimesWeb.front().first) &&
time <= (_triggerTimesWeb.back().first)
);
}
void WebFieldlinesWindow::getNewTriggerTimesWebList(double time) {
_worker.getRangeOfAvailableTriggerTimes(time, time, _triggerTimesWeb);
_nAvailableWeb = static_cast<int>(_triggerTimesWeb.size());
}
bool WebFieldlinesWindow::workerWindowIsReady() {
return _worker.windowIsComplete();
}
bool WebFieldlinesWindow::expectedWindowIsOutOfBounds(double time) {
auto resultForwards = std::find_if(
_triggerTimesWeb.rbegin(),
_triggerTimesWeb.rbegin() + _window.forwardWidth,
[time](auto pair) {
return time > pair.first;
});
}
);
auto resultBackwards = std::find_if(_triggerTimesWeb.begin(), _triggerTimesWeb.begin() + _window.backWidth, [time](auto pair) {
auto resultBackwards = std::find_if(
_triggerTimesWeb.begin(),
_triggerTimesWeb.begin() + _window.backWidth,
[time](auto pair) {
return time < pair.first;
});
}
);
return resultForwards != _triggerTimesWeb.rbegin() + _window.forwardWidth || resultBackwards != _triggerTimesWeb.begin() + _window.backWidth;
}
return resultForwards != _triggerTimesWeb.rbegin() + _window.forwardWidth ||
resultBackwards != _triggerTimesWeb.begin() + _window.backWidth;
}
void WebFieldlinesWindow::rfsHasUpdated() {
_worker.flagUpdated();
}
void WebFieldlinesWindow::rfsHasUpdated() {
_worker.flagUpdated();
}
bool WebFieldlinesWindow::checkWorkerEdgeMode(){
return _worker.edgeMode();
}
bool WebFieldlinesWindow::checkWorkerEdgeMode(){
return _worker.edgeMode();
}
bool WebFieldlinesWindow::edgeWindowReady(){
return _edgeWindowReady;
}
// -------------------------- PRIVATE FUNCTIONS -----------------------------------//
// Returns first trigger of window
double WebFieldlinesWindow::windowStart(){
return _window.triggerTimes.front().first;
}
// Returns last trigger of window
double WebFieldlinesWindow::windowEnd(){
return _window.triggerTimes.back().first;
}
bool WebFieldlinesWindow::edgeWindowReady(){
return _edgeWindowReady;
}
// Returns first trigger of window
double WebFieldlinesWindow::windowStart(){
return _window.triggerTimes.front().first;
}
// Returns last trigger of window
double WebFieldlinesWindow::windowEnd(){
return _window.triggerTimes.back().first;
}
} // namespace openspace

View File

@@ -39,156 +39,218 @@ namespace {
} // namespace
namespace openspace{
// CONSTRUCTOR
WebFieldlinesWorker::WebFieldlinesWorker(std::string syncDir, std::string serverUrl)
: _syncDir(syncDir), _serverUrl(serverUrl) {
// Maybe to be used
_endpointSingleDownload = _serverUrl; // should be set by argument to be more general [DEPRICATED FOR NOW, DO WE NEED THIS?]
}
// Destructor, deleting all files that were downloaded during the run.
WebFieldlinesWorker::~WebFieldlinesWorker() {
// Cancel any potential download
if (_downloading && _downloading->hasStarted())
_downloading->wait();
// Remove all files
std::vector<std::string> temp = ghoul::filesystem::Directory(_syncDir).readFiles();
// Sneaky check, just want to make sure it is only deleting fieldlines for now
if (temp.back().substr(temp.back().size() - 5) == "osfls" && temp.front().substr(temp.front().size() - 5) == "osfls") {
std::for_each(temp.begin(), temp.end(), [&](auto it) {
FileSys.deleteFile(it);
});
}
WebFieldlinesWorker::WebFieldlinesWorker(std::string syncDir, std::string serverUrl)
: _syncDir(syncDir), _serverUrl(serverUrl) {
// Maybe to be used
_endpointSingleDownload = _serverUrl;
// should be set by argument to be more general
// [DEPRICATED FOR NOW, DO WE NEED THIS?]
}
WebFieldlinesWorker::~WebFieldlinesWorker() {
// Deleting all files that were downloaded during the run.
// Cancel any potential download
if (_downloading && _downloading->hasStarted())
_downloading->wait();
// Remove all files
std::vector<std::string> temp =
ghoul::filesystem::Directory(_syncDir).readFiles();
// Sneaky check, just want to make sure it is only deleting fieldlines for now
if (temp.back().substr(temp.back().size() - 5) == "osfls" &&
temp.front().substr(temp.front().size() - 5) == "osfls")
{
std::for_each(temp.begin(), temp.end(), [&](auto it) {
FileSys.deleteFile(it);
});
}
}
// PUBLIC FUNCTIONS
void WebFieldlinesWorker::getRangeOfAvailableTriggerTimes(double startTime, double endTime, std::vector<std::pair<double, std::string>> &_triggerTimesWeb){
// PUBLIC FUNCTIONS
void WebFieldlinesWorker::getRangeOfAvailableTriggerTimes(double startTime,
double endTime,
std::vector<std::pair<double,
std::string>> &_triggerTimesWeb)
{
// We don't want to keep sending request, if we just get empty responses.
if (!_noMoreRequests) {
auto time = global::timeManager.time().ISO8601();
Time maxTime;
Time minTime;
// We don't want to keep sending request, if we just get empty responses.
if (!_noMoreRequests) {
auto time = global::timeManager.time().ISO8601();
Time maxTime;
Time minTime;
const int timeSpann = 2*86400; // The timespann we would like to request (in seconds) [ 1 day = 86400, 1 week = 604800 ]
const std::string dataID = "dataID";
const std::string files = "files";
std::string stringResult;
std::vector<std::string> urlList;
std::vector<std::string> timeList;
// The timespan we would like to request (in seconds)
// [ 1 day = 86400, 1 week = 604800 ]
const int timeSpan = 2*86400;
maxTime.setTime(time);
minTime.setTime(time);
maxTime.advanceTime(timeSpann);
minTime.advanceTime(-timeSpann);
const std::string dataID = "dataID";
const std::string files = "files";
std::string stringResult;
std::vector<std::string> urlList;
std::vector<std::string> timeList;
std::string url = _serverUrl + "&time.min=" + minTime.ISO8601() + "&time.max=" + maxTime.ISO8601();
SyncHttpMemoryDownload mmryDld = SyncHttpMemoryDownload(url);
HttpRequest::RequestOptions opt = {};
opt.requestTimeoutSeconds = 0;
mmryDld.download(opt);
maxTime.setTime(time);
minTime.setTime(time);
maxTime.advanceTime(timeSpan);
minTime.advanceTime(-timeSpan);
std::transform(mmryDld.downloadedData().begin(), mmryDld.downloadedData().end(), std::back_inserter(stringResult),
[](char c) {
std::string url = _serverUrl +
"&time.min=" + minTime.ISO8601() +
"&time.max=" + maxTime.ISO8601();
SyncHttpMemoryDownload mmryDld = SyncHttpMemoryDownload(url);
HttpRequest::RequestOptions opt = {};
opt.requestTimeoutSeconds = 0;
mmryDld.download(opt);
// TODO emiax: std::copy or similar should be possible here
std::transform(
mmryDld.downloadedData().begin(),
mmryDld.downloadedData().end(),
std::back_inserter(stringResult),
[](char c) {
return c;
});
auto res = json::parse(stringResult);
auto temp = std::move(_triggerTimesWeb);
_triggerTimesWeb.clear(); // Clear old big window
for (auto& elem : res[files]) {
timeList.push_back(elem["timestamp"]);
urlList.push_back(elem["url"]);
}
);
// Just want to make sure there is no error in the parsing, so taking the smallest dimension, but should be the same
for (int i = 0; i < std::min(timeList.size(), urlList.size()); i++) {
_triggerTimesWeb.push_back(std::make_pair(triggerTimeString2Double(timeList[i]), urlList[i]));
}
auto res = json::parse(stringResult);
auto temp = std::move(_triggerTimesWeb);
_triggerTimesWeb.clear(); // Clear old big window
std::sort(_triggerTimesWeb.begin(), _triggerTimesWeb.end()); // If by any chance it would not sort in properly
if (_triggerTimesWeb.size() == 0 || std::equal(temp.begin(),temp.end(),_triggerTimesWeb.begin(), _triggerTimesWeb.end())) // We got an empty response or the same response twice, stahp it
_strikes++;
if (_strikes % 2 == 0){ // We have got 2 strikes, no more requests for you, Mr.Sir.
_bigWindowHasData = (_triggerTimesWeb.size() > 0);
_noMoreRequests = true;
acceptableToStartRequestingAgain = std::make_pair(minTime.j2000Seconds(), maxTime.j2000Seconds());
}
for (auto& elem : res[files]) {
timeList.push_back(elem["timestamp"]);
urlList.push_back(elem["url"]);
}
// Just want to make sure there is no error in the parsing,
// so taking the smallest dimension, but should be the same
for (int i = 0; i < std::min(timeList.size(), urlList.size()); i++) {
_triggerTimesWeb.push_back(
std::make_pair(triggerTimeString2Double(timeList[i]), urlList[i])
);
}
std::sort(_triggerTimesWeb.begin(), _triggerTimesWeb.end());
// If by any chance it would not sort in properly
if (_triggerTimesWeb.size() == 0 ||
std::equal(temp.begin(),
temp.end(),
_triggerTimesWeb.begin(),
_triggerTimesWeb.end()
)
) { // We got an empty response or the same response twice, stahp it
_strikes++;
}
// We have got 2 strikes, no more requests for you, Mr.Sir.
if (_strikes % 2 == 0) {
_bigWindowHasData = (_triggerTimesWeb.size() > 0);
_noMoreRequests = true;
acceptableToStartRequestingAgain =
std::make_pair(minTime.j2000Seconds(), maxTime.j2000Seconds());
}
}
}
// Download all files in the current window
// This function starts usually in the middle of the window and proceeds to download all
// future timesteps, then steps backwards from the startingpoint
// TODO(Axel): Different behaviour depending on direction the user is moving in,
// might be wanted?
void WebFieldlinesWorker::downloadWindow(
std::vector<std::pair<double, std::string>> triggerTimes)
{
// Helper variables
int startingPoint = triggerTimes.size() / 2;
bool downloaded = false;
bool oneUpdate = false;
bool fastDownload = global::timeManager.deltaTime() > 1800.0;
if (fastDownload) {
startingPoint = triggerTimes.size() - 1;
}
// Download all files in the current window
// This function starts usually in the middle of the window and proceeds to download all future timesteps,
// then steps backwards from the startingpoint
//TODO(Axel): Different behaviour depending on direction the user is moving in, might be wanted?
void WebFieldlinesWorker::downloadWindow(std::vector<std::pair<double, std::string>> triggerTimes) {
// Helper variables
int startingPoint = triggerTimes.size() / 2;
bool downloaded = false;
bool oneUpdate = false;
bool fastDownload = global::timeManager.deltaTime() > 1800.0;
// Is there a download thread to be joined and added to the list?
if (_downloading && _downloading->hasSucceeded() && _newWindow) {
_downloading->wait();
addToDownloadedList(_latestDownload);
_readyToDownload = true;
// This is to trigger one update of the fieldline timestamp that the user is
// currently on, while the rest of them will be downloaded in the background,
// and updated once ready
if (_latestDownload.second == triggerTimes[startingPoint].second)
oneUpdate = true;
}
if (fastDownload) startingPoint = triggerTimes.size() - 1;
if (_readyToDownload) {
// Forwards
std::vector<std::pair<double, std::string>>::iterator forwardIt =
triggerTimes.begin();
// Is there a download thread to be joined and added to the list?
if (_downloading && _downloading->hasSucceeded() && _newWindow) {
_downloading->wait();
addToDownloadedList(_latestDownload);
_readyToDownload = true;
// This is to trigger one update of the fieldline timestamp that the user is currently on,
// while the rest of them will be downloaded in the background, and updated once ready
if (_latestDownload.second == triggerTimes[startingPoint].second)
oneUpdate = true;
}
std::advance(forwardIt, startingPoint);
std::for_each(forwardIt, triggerTimes.end(), [this, &downloaded](auto it) {
if (!downloaded && !fileIsOnDisk(it.first)) {
downloadOsfls(it);
downloaded = true;
_doneUpdating = false;
}
});
if (_readyToDownload) {
// Forwards
std::vector<std::pair<double, std::string>>::iterator forwardIt = triggerTimes.begin();
std::advance(forwardIt, startingPoint);
std::for_each(forwardIt, triggerTimes.end(), [this, &downloaded](auto it) {
if (!downloaded && !fileIsOnDisk(it.first)) {
downloadOsfls(it);
downloaded = true;
_doneUpdating = false;
}
});
// Backwards
if (!downloaded) {
std::for_each(triggerTimes.rbegin(), triggerTimes.rend(), [this, &downloaded](auto it) {
// Backwards
if (!downloaded) {
std::for_each(
triggerTimes.rbegin(),
triggerTimes.rend(),
[this, &downloaded](auto it) {
if (!downloaded && !fileIsOnDisk(it.first)) {
downloadOsfls(it);
downloaded = true;
_doneUpdating = false;
}
});
}
}
if ((!downloaded && !_doneUpdating && _newWindow && _readyToDownload && _downloadedSomething) || oneUpdate && _downloadedSomething) {
// If reach this point, we now know that we have downloaded all the sets
_readyToUpdateSourceFiles = true;
if(!oneUpdate)
_newWindow = false;
oneUpdate = false;
}
);
}
}
// Updates the list of available sourcefiles, owned by renderablefieldlinessequence.
void WebFieldlinesWorker::updateRFSSourceFiles(std::vector<std::string>& _sourceFiles) {
if (_readyToUpdateSourceFiles) {
std::vector<std::string> toInsert;
std::transform(_downloadedTriggerTimes.begin(), _downloadedTriggerTimes.end(), std::back_inserter(toInsert), [this](auto const& pair) { return _syncDir + FileSys.PathSeparator + pair.second; });
auto sourcePtr = _sourceFiles.begin();
std::for_each(toInsert.begin(), toInsert.end(), [&sourcePtr, &_sourceFiles](auto insertableElement) {
if ((!downloaded &&
!_doneUpdating &&
_newWindow &&
_readyToDownload &&
_downloadedSomething) ||
oneUpdate && _downloadedSomething)
{
// If reach this point, we now know that we have downloaded all the sets
_readyToUpdateSourceFiles = true;
if (!oneUpdate) {
_newWindow = false;
}
oneUpdate = false;
}
}
// Updates the list of available sourcefiles, owned by renderablefieldlinessequence.
void WebFieldlinesWorker::updateRFSSourceFiles(std::vector<std::string>& _sourceFiles) {
if (_readyToUpdateSourceFiles) {
std::vector<std::string> toInsert;
std::transform(
_downloadedTriggerTimes.begin(),
_downloadedTriggerTimes.end(),
std::back_inserter(toInsert),
[this] (auto const& pair) {
return _syncDir + FileSys.PathSeparator + pair.second;
}
);
auto sourcePtr = _sourceFiles.begin();
std::for_each(
toInsert.begin(),
toInsert.end(),
[&sourcePtr, &_sourceFiles] (auto insertableElement) {
for (sourcePtr; sourcePtr != _sourceFiles.end(); sourcePtr++) {
if (sourcePtr != (--_sourceFiles.end())) {
if (insertableElement > *sourcePtr && insertableElement < *sourcePtr++) {
if (insertableElement > *sourcePtr &&
insertableElement < *sourcePtr++)
{
_sourceFiles.insert(sourcePtr++, insertableElement);
break;
}
@@ -204,122 +266,158 @@ namespace openspace{
if (sourcePtr == _sourceFiles.end()) {
sourcePtr = _sourceFiles.insert(sourcePtr, insertableElement);
}
});
}
);
// Set flags to let anyone interested know that this has been done.
_readyToUpdateSourceFiles = false;
_doneUpdating = true;
}
// Set flags to let anyone interested know that this has been done.
_readyToUpdateSourceFiles = false;
_doneUpdating = true;
}
}
}
bool WebFieldlinesWorker::windowIsComplete(){
return _doneUpdating;
}
bool WebFieldlinesWorker::windowIsComplete() {
return _doneUpdating;
}
void WebFieldlinesWorker::flagUpdated() {
_doneUpdating = false;
}
void WebFieldlinesWorker::flagUpdated() {
_doneUpdating = false;
}
void WebFieldlinesWorker::newWindowToDownload(){
_newWindow = true;
_downloadedSomething = false;
}
void WebFieldlinesWorker::newWindowToDownload() {
_newWindow = true;
_downloadedSomething = false;
}
bool WebFieldlinesWorker::edgeMode(){
if (global::timeManager.time().j2000Seconds() < acceptableToStartRequestingAgain.first || global::timeManager.time().j2000Seconds() > acceptableToStartRequestingAgain.second) {
_noMoreRequests = false;
_bigWindowHasData = false;
}
return _noMoreRequests && _bigWindowHasData;
bool WebFieldlinesWorker::edgeMode() {
const double currentTime = global::timeManager.time().j2000Seconds();
if (currentTime < acceptableToStartRequestingAgain.first ||
currentTime > acceptableToStartRequestingAgain.second)
{
_noMoreRequests = false;
_bigWindowHasData = false;
}
return _noMoreRequests && _bigWindowHasData;
}
std::string WebFieldlinesWorker::downloadOsfls(std::pair<double,std::string> downloadKey){
_downloadedSomething = true;
_latestDownload = downloadKey;
// YYYY-MM-DDTHH-MM-SS.sss.osfls - Might change
const int fileNameLength = 29;
const std::string fileName = downloadKey.second.substr(downloadKey.second.size()-fileNameLength);
std::string url = downloadKey.second;
std::string destinationpath = absPath(_syncDir + ghoul::filesystem::FileSystem::PathSeparator + fileName); // what the downloaded filename is to be
_downloading = std::make_unique<AsyncHttpFileDownload>(url, destinationpath, HttpFileDownload::Overwrite::Yes);
HttpRequest::RequestOptions opt = {};
opt.requestTimeoutSeconds = 0;
_downloading->start(opt);
_readyToDownload = false;
return destinationpath;
}
std::string WebFieldlinesWorker::downloadOsfls(std::pair<double,std::string> downloadKey)
{
_downloadedSomething = true;
_latestDownload = downloadKey;
// This function searches for triggerTime in _downloadedTriggerTimes,
// to see weather a file has already been downloaded or not
bool WebFieldlinesWorker::fileIsOnDisk(double triggerTime){
if(std::find_if(_downloadedTriggerTimes.begin(), _downloadedTriggerTimes.end(),
[&triggerTime](std::pair<double, std::string> const &element){
// YYYY-MM-DDTHH-MM-SS.sss.osfls - Might change
const int fileNameLength = 29;
const std::string fileName =
downloadKey.second.substr(downloadKey.second.size() - fileNameLength);
std::string url = downloadKey.second;
std::string destinationPath =
absPath(_syncDir + ghoul::filesystem::FileSystem::PathSeparator + fileName);
// what the downloaded filename is to be
_downloading = std::make_unique<AsyncHttpFileDownload>(
url, destinationPath, HttpFileDownload::Overwrite::Yes
);
HttpRequest::RequestOptions opt = {};
opt.requestTimeoutSeconds = 0;
_downloading->start(opt);
_readyToDownload = false;
return destinationPath;
}
// This function searches for triggerTime in _downloadedTriggerTimes,
// to see weather a file has already been downloaded or not
bool WebFieldlinesWorker::fileIsOnDisk(double triggerTime) {
return std::find_if(
_downloadedTriggerTimes.begin(),
_downloadedTriggerTimes.end(),
[&triggerTime] (std::pair<double, std::string> const &element) {
return element.first == triggerTime;
}) != _downloadedTriggerTimes.end())
return true;
else
return false;
}
}) != _downloadedTriggerTimes.end();
}
void WebFieldlinesWorker::checkForExistingData(std::vector<std::tuple<double, std::string, int>>& _triggerTimesWeb,
std::vector<std::pair<double, std::string>>& _triggerTimesOnDisk){
int indexWeb = 0;
int indexDisk = 0;
while(true){
if(compareTimetriggersEqual(std::get<0>(_triggerTimesWeb[indexWeb]), _triggerTimesOnDisk[indexDisk].first)){
std::get<1>(_triggerTimesWeb[indexWeb]) = _triggerTimesOnDisk[indexDisk].second;
}
void WebFieldlinesWorker::checkForExistingData(
std::vector<std::tuple<double, std::string, int>>& _triggerTimesWeb,
std::vector<std::pair<double, std::string>>& _triggerTimesOnDisk)
{
int indexWeb = 0;
int indexDisk = 0;
// TODO emiax: This looks like an infinite loop.
// Need a way to break out from this when destroying the worker..?
while (true) {
if (compareTimetriggersEqual(
std::get<0>(_triggerTimesWeb[indexWeb]),
_triggerTimesOnDisk[indexDisk].first
)) {
std::get<1>(_triggerTimesWeb[indexWeb]) =
_triggerTimesOnDisk[indexDisk].second;
}
}
}
// PRIVATE FUNCTIONS
void WebFieldlinesWorker::parseTriggerTimesList(std::string s, std::vector<std::tuple<double, std::string, int>> &_triggerTimesWeb){
// Turn into stringstream to parse the comma-delimited string into vector
std::stringstream ss(s);
char c;
std::string sub;
while(ss >> c)
{
if (c == '[' || c == ']' || c == '"' ) continue;
else if (c == ','){
_triggerTimesWeb.push_back(std::make_tuple(triggerTimeString2Double(sub), sub, -1));
sub.clear();
}
else sub += c;
void WebFieldlinesWorker::parseTriggerTimesList(std::string s,
std::vector<std::tuple<double, std::string, int>> &_triggerTimesWeb)
{
// Turn into stringstream to parse the comma-delimited string into vector
std::stringstream ss(s);
char c;
std::string sub;
while(ss >> c) {
if (c == '[' || c == ']' || c == '"') {
continue;
}
_triggerTimesWeb.push_back(std::make_tuple(triggerTimeString2Double(sub), sub, -1));
}
double WebFieldlinesWorker::triggerTimeString2Double(std::string s){
s.replace(13, 1, ":");
s.replace(16, 1, ":");
Time time = Time();
time.setTime(s);
return (time.j2000Seconds() /*- 69.185013294*/); // openspace timeconverter gives an error. but we're gonna be consistent with the error
}
void WebFieldlinesWorker::triggerTimeDouble2String(double i, std::string& s){
double temp = i /*+ 69.185013294*/;
Time time = Time();
time.setTime(temp);
s = time.ISO8601();
s.replace(13, 1, "-");
s.replace(16, 1, "-");
}
// Inserts the pair in sorted order
void WebFieldlinesWorker::addToDownloadedList(std::pair<double, std::string> pair){
const std::string fileName = pair.second.substr(pair.second.size() - 29);
_downloadedTriggerTimes.insert(std::upper_bound(_downloadedTriggerTimes.begin(),_downloadedTriggerTimes.end(),pair),std::make_pair(pair.first, fileName));
if (c == ',') {
_triggerTimesWeb.push_back(
std::make_tuple(triggerTimeString2Double(sub), sub, -1)
);
sub.clear();
}
else {
sub += c;
}
}
bool WebFieldlinesWorker::compareTimetriggersEqual(double first, double second){
double eps = 100.0;
if(first > second - eps && first < second + eps) return true;
return false;
}
_triggerTimesWeb.push_back(std::make_tuple(triggerTimeString2Double(sub), sub, -1));
}
double WebFieldlinesWorker::triggerTimeString2Double(std::string s){
s.replace(13, 1, ":");
s.replace(16, 1, ":");
Time time = Time();
time.setTime(s);
return time.j2000Seconds() /*- 69.185013294*/;
// openspace timeconverter gives an error.
// but we're gonna be consistent with the error
}
void WebFieldlinesWorker::triggerTimeDouble2String(double i, std::string& s) {
double temp = i /*+ 69.185013294*/;
Time time = Time();
time.setTime(temp);
s = time.ISO8601();
s.replace(13, 1, "-");
s.replace(16, 1, "-");
}
// Inserts the pair in sorted order
void WebFieldlinesWorker::addToDownloadedList(std::pair<double, std::string> pair) {
const std::string fileName = pair.second.substr(pair.second.size() - 29);
_downloadedTriggerTimes.insert(
std::upper_bound(
_downloadedTriggerTimes.begin(), _downloadedTriggerTimes.end(), pair
), std::make_pair(pair.first, fileName)
);
}
bool WebFieldlinesWorker::compareTimetriggersEqual(double first, double second) {
const double eps = 100.0;
return first > second - eps && first < second + eps;
}
} // namespace openspace