Make URLSynchronization and HTTPSynchronization download into temporary files and if the download succeeds, transactionally move the temporary file into the correct destination

This commit is contained in:
Alexander Bock
2018-03-10 05:08:14 -05:00
parent 5b6ae62bab
commit 31cdee1fa1
5 changed files with 78 additions and 14 deletions
+34 -10
View File
@@ -22,27 +22,27 @@
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include "httpsynchronization.h"
#include <modules/sync/syncs/httpsynchronization.h>
#include <modules/sync/syncmodule.h>
#include <openspace/documentation/verifier.h>
#include <openspace/engine/openspaceengine.h>
#include <openspace/engine/moduleengine.h>
#include <openspace/util/httprequest.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/filesystem/filesystem.h>
#include <openspace/documentation/verifier.h>
#include <sstream>
#include <ghoul/logging/logmanager.h>
#include <cstdio>
#include <fstream>
#include <numeric>
#include <memory>
#include <sstream>
namespace {
constexpr const char* KeyIdentifier = "Identifier";
constexpr const char* KeyVersion = "Version";
constexpr const char* TempSuffix = ".tmp";
constexpr const char* QueryKeyIdentifier = "identifier";
constexpr const char* QueryKeyFileVersion = "file_version";
constexpr const char* QueryKeyApplicationVersion = "application_version";
@@ -214,8 +214,8 @@ bool HttpSynchronization::trySyncFromUrl(std::string listUrl) {
std::string filename = line.substr(lastSlash + 1);
std::string fileDestination = directory() +
ghoul::filesystem::FileSystem::PathSeparator +
filename;
ghoul::filesystem::FileSystem::PathSeparator +
filename + TempSuffix;
downloads.push_back(std::make_unique<AsyncHttpFileDownload>(
line, fileDestination, HttpFileDownload::Overwrite::Yes));
@@ -256,7 +256,31 @@ bool HttpSynchronization::trySyncFromUrl(std::string listUrl) {
bool failed = false;
for (std::unique_ptr<AsyncHttpFileDownload>& d : downloads) {
d->wait();
if (!d->hasSucceeded()) {
if (d->hasSucceeded()) {
// If we are forcing the override, we download to a temporary file
// first, so when we are done here, we need to rename the file to the
// original name
const std::string& tempName = d->destination();
std::string originalName = tempName.substr(
0,
tempName.size() - strlen(TempSuffix)
);
FileSys.deleteFile(originalName);
int success = rename(tempName.c_str(), originalName.c_str());
if (success != 0) {
LERRORC(
"URLSynchronization",
fmt::format(
"Error renaming file {} to {}", tempName, originalName
)
);
failed = true;
}
}
else {
failed = true;
}
}
+30 -4
View File
@@ -35,11 +35,14 @@
#include <fstream>
#include <numeric>
#include <memory>
#include <cstdio>
namespace {
constexpr const char* KeyUrl = "Url";
constexpr const char* KeyIdentifier = "Identifier";
constexpr const char* KeyOverride = "Override";
constexpr const char* TempSuffix = ".tmp";
} // namespace
namespace openspace {
@@ -149,7 +152,7 @@ void UrlSynchronization::start() {
std::string fileDestination = directory() +
ghoul::filesystem::FileSystem::PathSeparator +
filename;
filename += TempSuffix;
std::unique_ptr<AsyncHttpFileDownload> download =
std::make_unique<AsyncHttpFileDownload>(
@@ -189,7 +192,6 @@ void UrlSynchronization::start() {
HttpRequest::RequestOptions opt;
opt.requestTimeoutSeconds = 0;
fileDownload->start(opt);
}
startedAllDownloads = true;
@@ -197,7 +199,31 @@ void UrlSynchronization::start() {
bool failed = false;
for (std::unique_ptr<AsyncHttpFileDownload>& d : downloads) {
d->wait();
if (!d->hasSucceeded()) {
if (d->hasSucceeded()) {
// If we are forcing the override, we download to a temporary file first,
// so when we are done here, we need to rename the file to the original
// name
const std::string& tempName = d->destination();
std::string originalName = tempName.substr(
0,
tempName.size() - strlen(TempSuffix)
);
FileSys.deleteFile(originalName);
int success = rename(tempName.c_str(), originalName.c_str());
if (success != 0) {
LERRORC(
"URLSynchronization",
fmt::format(
"Error renaming file {} to {}", tempName, originalName
)
);
failed = true;
}
}
else {
failed = true;
}
}
@@ -206,7 +232,7 @@ void UrlSynchronization::start() {
createSyncFile();
}
else {
for (auto& d : downloads) {
for (std::unique_ptr<AsyncHttpFileDownload>& d : downloads) {
d->cancel();
}
}