From 65e87c6c70fc1e5af8f0c3fb762ca13e6aa6a8e4 Mon Sep 17 00:00:00 2001 From: Alexander Tkachev Date: Sat, 18 Jun 2016 19:35:57 +0600 Subject: CLOUD: Update save's timestamp on rewrite This commit moves save/load timestamps static methods into DefaultSaveFileManager and fixes a few related bugs. --- backends/cloud/savessyncrequest.cpp | 133 +++++-------------------------- backends/cloud/savessyncrequest.h | 8 +- backends/saves/default/default-saves.cpp | 109 +++++++++++++++++++++++++ backends/saves/default/default-saves.h | 14 +++- 4 files changed, 142 insertions(+), 122 deletions(-) (limited to 'backends') diff --git a/backends/cloud/savessyncrequest.cpp b/backends/cloud/savessyncrequest.cpp index f059e29a8d..4d18647911 100644 --- a/backends/cloud/savessyncrequest.cpp +++ b/backends/cloud/savessyncrequest.cpp @@ -29,11 +29,10 @@ #include "common/savefile.h" #include "common/system.h" #include "gui/saveload-dialog.h" +#include namespace Cloud { -const char *SavesSyncRequest::TIMESTAMPS_FILENAME = "timestamps"; - SavesSyncRequest::SavesSyncRequest(Storage *storage, Storage::BoolCallback callback, Networking::ErrorCallback ecb): Request(nullptr, ecb), CommandSender(nullptr), _storage(storage), _boolCallback(callback), _workingRequest(nullptr), _ignoreCallback(false) { @@ -59,7 +58,7 @@ void SavesSyncRequest::start() { _ignoreCallback = false; //load timestamps - loadTimestamps(); + _localFilesTimestamps = DefaultSaveFileManager::loadTimestamps(); //list saves directory Common::String dir = _storage->savesDirectoryPath(); @@ -90,25 +89,23 @@ void SavesSyncRequest::directoryListedCallback(Storage::ListDirectoryResponse re StorageFile &file = remoteFiles[i]; if (file.isDirectory()) continue; totalSize += file.size(); - if (file.name() == TIMESTAMPS_FILENAME) continue; + if (file.name() == DefaultSaveFileManager::TIMESTAMPS_FILENAME) continue; Common::String name = file.name(); if (!_localFilesTimestamps.contains(name)) _filesToDownload.push_back(file); else { localFileNotAvailableInCloud[name] = false; - - if (_localFilesTimestamps[name] != INVALID_TIMESTAMP) { - if (_localFilesTimestamps[name] == file.timestamp()) - continue; - - //we actually can have some files not only with timestamp < remote - //but also with timestamp > remote (when we have been using ANOTHER CLOUD and then switched back) - if (_localFilesTimestamps[name] < file.timestamp()) - _filesToDownload.push_back(file); - else - _filesToUpload.push_back(file.name()); - } + + if (_localFilesTimestamps[name] == file.timestamp()) + continue; + + //we actually can have some files not only with timestamp < remote + //but also with timestamp > remote (when we have been using ANOTHER CLOUD and then switched back) + if (_localFilesTimestamps[name] > file.timestamp() || _localFilesTimestamps[name] == DefaultSaveFileManager::INVALID_TIMESTAMP) + _filesToUpload.push_back(file.name()); + else + _filesToDownload.push_back(file); } } @@ -116,7 +113,7 @@ void SavesSyncRequest::directoryListedCallback(Storage::ListDirectoryResponse re //upload files which are unavailable in cloud for (Common::HashMap::iterator i = localFileNotAvailableInCloud.begin(); i != localFileNotAvailableInCloud.end(); ++i) { - if (i->_key == TIMESTAMPS_FILENAME) continue; + if (i->_key == DefaultSaveFileManager::TIMESTAMPS_FILENAME) continue; if (i->_value) _filesToUpload.push_back(i->_key); } @@ -234,7 +231,7 @@ void SavesSyncRequest::downloadNextFile() { /////// debug("downloading %s (%d %%)", _currentDownloadingFile.name().c_str(), (int)(getProgress() * 100)); /////// - _workingRequest = _storage->downloadById(_currentDownloadingFile.id(), concatWithSavesPath(_currentDownloadingFile.name()), + _workingRequest = _storage->downloadById(_currentDownloadingFile.id(), DefaultSaveFileManager::concatWithSavesPath(_currentDownloadingFile.name()), new Common::Callback(this, &SavesSyncRequest::fileDownloadedCallback), new Common::Callback(this, &SavesSyncRequest::fileDownloadedErrorCallback) ); @@ -252,7 +249,9 @@ void SavesSyncRequest::fileDownloadedCallback(Storage::BoolResponse response) { } //update local timestamp for downloaded file + _localFilesTimestamps = DefaultSaveFileManager::loadTimestamps(); _localFilesTimestamps[_currentDownloadingFile.name()] = _currentDownloadingFile.timestamp(); + DefaultSaveFileManager::saveTimestamps(_localFilesTimestamps); //continue downloading files downloadNextFile(); @@ -290,7 +289,9 @@ void SavesSyncRequest::fileUploadedCallback(Storage::UploadResponse response) { if (_ignoreCallback) return; //update local timestamp for the uploaded file + _localFilesTimestamps = DefaultSaveFileManager::loadTimestamps(); _localFilesTimestamps[_currentUploadingFile] = response.value.timestamp(); + DefaultSaveFileManager::saveTimestamps(_localFilesTimestamps); //continue uploading files uploadNextFile(); @@ -342,112 +343,16 @@ Common::Array SavesSyncRequest::getFilesToDownload() { void SavesSyncRequest::finishError(Networking::ErrorResponse error) { debug("SavesSync::finishError"); - //save updated timestamps (even if Request failed, there would be only valid timestamps) - saveTimestamps(); - Request::finishError(error); } void SavesSyncRequest::finishSuccess(bool success) { Request::finishSuccess(); - //save updated timestamps (even if Request failed, there would be only valid timestamps) - saveTimestamps(); - //update last successful sync date CloudMan.setStorageLastSync(CloudMan.getStorageIndex(), _date); if (_boolCallback) (*_boolCallback)(Storage::BoolResponse(this, success)); } -void SavesSyncRequest::loadTimestamps() { - //refresh the files list - Common::Array files; - g_system->getSavefileManager()->updateSavefilesList(files); - - //start with listing all the files in saves/ directory and setting invalid timestamp to them - Common::StringArray localFiles = g_system->getSavefileManager()->listSavefiles("*"); - for (uint32 i = 0; i < localFiles.size(); ++i) - _localFilesTimestamps[localFiles[i]] = INVALID_TIMESTAMP; - - //now actually load timestamps from file - Common::InSaveFile *file = g_system->getSavefileManager()->openRawFile(TIMESTAMPS_FILENAME); - if (!file) { - warning("SavesSyncRequest: failed to open '%s' file to load timestamps", TIMESTAMPS_FILENAME); - return; - } - - while (!file->eos()) { - //read filename into buffer (reading until the first ' ') - Common::String buffer; - while (!file->eos()) { - byte b = file->readByte(); - if (b == ' ') break; - buffer += (char)b; - } - - //read timestamp info buffer (reading until ' ' or some line ending char) - Common::String filename = buffer; - bool lineEnded = false; - buffer = ""; - while (!file->eos()) { - byte b = file->readByte(); - if (b == ' ' || b == '\n' || b == '\r') { - lineEnded = (b == '\n'); - break; - } - buffer += (char)b; - } - - //parse timestamp - uint timestamp = atol(buffer.c_str()); - if (buffer == "" || timestamp == 0) break; - _localFilesTimestamps[filename] = timestamp; - - //read until the end of the line - if (!lineEnded) { - while (!file->eos()) { - byte b = file->readByte(); - if (b == '\n') break; - } - } - } - - delete file; -} - -void SavesSyncRequest::saveTimestamps() { - Common::DumpFile f; - Common::String filename = concatWithSavesPath(TIMESTAMPS_FILENAME); - if (!f.open(filename, true)) { - warning("SavesSyncRequest: failed to open '%s' file to save timestamps", filename.c_str()); - return; - } - - for (Common::HashMap::iterator i = _localFilesTimestamps.begin(); i != _localFilesTimestamps.end(); ++i) { - Common::String data = i->_key + Common::String::format(" %u\n", i->_value); - if (f.write(data.c_str(), data.size()) != data.size()) { - warning("SavesSyncRequest: failed to write timestamps data into '%s'", filename.c_str()); - return; - } - } - - f.close(); -} - -Common::String SavesSyncRequest::concatWithSavesPath(Common::String name) { - Common::String path = ConfMan.get("savepath"); - if (path.size() > 0 && (path.lastChar() == '/' || path.lastChar() == '\\')) - return path + name; - - //simple heuristic to determine which path separator to use - int backslashes = 0; - for (uint32 i = 0; i < path.size(); ++i) - if (path[i] == '/') --backslashes; - else if (path[i] == '\\') ++backslashes; - - if (backslashes) return path + '\\' + name; - return path + '/' + name; -} - } // End of namespace Cloud diff --git a/backends/cloud/savessyncrequest.h b/backends/cloud/savessyncrequest.h index 105d7f7f65..19e67d9dd8 100644 --- a/backends/cloud/savessyncrequest.h +++ b/backends/cloud/savessyncrequest.h @@ -28,14 +28,10 @@ #include "common/hashmap.h" #include "common/hash-str.h" #include "gui/object.h" -#include namespace Cloud { class SavesSyncRequest: public Networking::Request, public GUI::CommandSender { - const uint32 INVALID_TIMESTAMP = UINT_MAX; - static const char *TIMESTAMPS_FILENAME; - Storage *_storage; Storage::BoolCallback _boolCallback; Common::HashMap _localFilesTimestamps; @@ -61,9 +57,7 @@ class SavesSyncRequest: public Networking::Request, public GUI::CommandSender { void uploadNextFile(); virtual void finishError(Networking::ErrorResponse error); void finishSuccess(bool success); - void loadTimestamps(); - void saveTimestamps(); - Common::String concatWithSavesPath(Common::String name); + public: SavesSyncRequest(Storage *storage, Storage::BoolCallback callback, Networking::ErrorCallback ecb); virtual ~SavesSyncRequest(); diff --git a/backends/saves/default/default-saves.cpp b/backends/saves/default/default-saves.cpp index e20ce31d18..54dc1c2966 100644 --- a/backends/saves/default/default-saves.cpp +++ b/backends/saves/default/default-saves.cpp @@ -29,6 +29,7 @@ #ifdef USE_CLOUD #include "backends/cloud/cloudmanager.h" +#include "common/file.h" #endif #if !defined(DISABLE_DEFAULT_SAVEFILEMANAGER) @@ -46,6 +47,10 @@ #include // for removeSavefile() #endif +#ifdef USE_CLOUD +const char *DefaultSaveFileManager::TIMESTAMPS_FILENAME = "timestamps"; +#endif + DefaultSaveFileManager::DefaultSaveFileManager() { } @@ -142,6 +147,13 @@ Common::OutSaveFile *DefaultSaveFileManager::openForSaving(const Common::String } } +#ifdef USE_CLOUD + // Update file's timestamp + Common::HashMap timestamps = loadTimestamps(); + timestamps[filename] = INVALID_TIMESTAMP; + saveTimestamps(timestamps); +#endif + // Obtain node. SaveFileCache::const_iterator file = _saveFileCache.find(filename); Common::FSNode fileNode; @@ -266,4 +278,101 @@ void DefaultSaveFileManager::assureCached(const Common::String &savePathName) { _cachedDirectory = savePathName; } +#ifdef USE_CLOUD + +Common::HashMap DefaultSaveFileManager::loadTimestamps() { + Common::HashMap timestamps; + + //refresh the files list + Common::Array files; + g_system->getSavefileManager()->updateSavefilesList(files); + + //start with listing all the files in saves/ directory and setting invalid timestamp to them + Common::StringArray localFiles = g_system->getSavefileManager()->listSavefiles("*"); + for (uint32 i = 0; i < localFiles.size(); ++i) + timestamps[localFiles[i]] = INVALID_TIMESTAMP; + + //now actually load timestamps from file + Common::InSaveFile *file = g_system->getSavefileManager()->openRawFile(TIMESTAMPS_FILENAME); + if (!file) { + warning("DefaultSaveFileManager: failed to open '%s' file to load timestamps", TIMESTAMPS_FILENAME); + return timestamps; + } + + while (!file->eos()) { + //read filename into buffer (reading until the first ' ') + Common::String buffer; + while (!file->eos()) { + byte b = file->readByte(); + if (b == ' ') break; + buffer += (char)b; + } + + //read timestamp info buffer (reading until ' ' or some line ending char) + Common::String filename = buffer; + while (true) { + bool lineEnded = false; + buffer = ""; + while (!file->eos()) { + byte b = file->readByte(); + if (b == ' ' || b == '\n' || b == '\r') { + lineEnded = (b == '\n'); + break; + } + buffer += (char)b; + } + + if (buffer == "" && file->eos()) break; + if (!lineEnded) filename += " " + buffer; + else break; + } + + //parse timestamp + uint32 timestamp = buffer.asUint64(); + if (buffer == "" || timestamp == 0) break; + timestamps[filename] = timestamp; + } + + delete file; + return timestamps; +} + +void DefaultSaveFileManager::saveTimestamps(Common::HashMap ×tamps) { + Common::DumpFile f; + Common::String filename = concatWithSavesPath(TIMESTAMPS_FILENAME); + if (!f.open(filename, true)) { + warning("DefaultSaveFileManager: failed to open '%s' file to save timestamps", filename.c_str()); + return; + } + + for (Common::HashMap::iterator i = timestamps.begin(); i != timestamps.end(); ++i) { + Common::String data = i->_key + Common::String::format(" %u\n", i->_value); + if (f.write(data.c_str(), data.size()) != data.size()) { + warning("DefaultSaveFileManager: failed to write timestamps data into '%s'", filename.c_str()); + return; + } + } + + f.flush(); + f.finalize(); + f.close(); +} + +Common::String DefaultSaveFileManager::concatWithSavesPath(Common::String name) { + Common::String path = ConfMan.get("savepath"); + if (path.size() > 0 && (path.lastChar() == '/' || path.lastChar() == '\\')) + return path + name; + + //simple heuristic to determine which path separator to use + int backslashes = 0; + for (uint32 i = 0; i < path.size(); ++i) + if (path[i] == '/') --backslashes; + else if (path[i] == '\\') ++backslashes; + + if (backslashes) return path + '\\' + name; + return path + '/' + name; +} + +#endif // ifdef USE_CLOUD + #endif // !defined(DISABLE_DEFAULT_SAVEFILEMANAGER) diff --git a/backends/saves/default/default-saves.h b/backends/saves/default/default-saves.h index af30cf45e9..e9edfb1f36 100644 --- a/backends/saves/default/default-saves.h +++ b/backends/saves/default/default-saves.h @@ -27,7 +27,8 @@ #include "common/savefile.h" #include "common/str.h" #include "common/fs.h" -#include "common/hashmap.h" +#include "common/hash-str.h" +#include /** * Provides a default savefile manager implementation for common platforms. @@ -44,6 +45,17 @@ public: virtual Common::OutSaveFile *openForSaving(const Common::String &filename, bool compress = true); virtual bool removeSavefile(const Common::String &filename); +#ifdef USE_CLOUD + + static const uint32 INVALID_TIMESTAMP = UINT_MAX; + static const char *TIMESTAMPS_FILENAME; + + static Common::HashMap loadTimestamps(); + static void saveTimestamps(Common::HashMap ×tamps); + static Common::String concatWithSavesPath(Common::String name); + +#endif + protected: /** * Get the path to the savegame directory. -- cgit v1.2.3