diff --git a/traffxml/CMakeLists.txt b/traffxml/CMakeLists.txt index 2db32693a..93b4937d3 100644 --- a/traffxml/CMakeLists.txt +++ b/traffxml/CMakeLists.txt @@ -7,6 +7,8 @@ set(SRC traff_model.hpp traff_model_xml.cpp traff_model_xml.hpp + traff_storage.cpp + traff_storage.hpp ) omim_add_library(${PROJECT_NAME} ${SRC}) diff --git a/traffxml/traff_storage.cpp b/traffxml/traff_storage.cpp new file mode 100644 index 000000000..50fbb1038 --- /dev/null +++ b/traffxml/traff_storage.cpp @@ -0,0 +1,76 @@ +#include "traffxml/traff_storage.hpp" + +#include "platform/platform.hpp" + +#include "coding/internal/file_data.hpp" + +#include "base/logging.hpp" + +#include + +namespace +{ +std::string GetFilePath(std::string const & fileName) { return GetPlatform().WritablePathForFile(fileName); } +} // namespace + +namespace traffxml +{ +// StorageLocal ------------------------------------------------------------------------------------ +bool LocalStorage::Save(pugi::xml_document const & doc) +{ + auto const filePath = GetFilePath(m_fileName); + + std::lock_guard guard(m_mutex); + + return base::WriteToTempAndRenameToFile(filePath, [&doc](std::string const & fileName) { + return doc.save_file(fileName.data(), " " /* indent */); + }); +} + +bool LocalStorage::Load(pugi::xml_document & doc) +{ + auto const filePath = GetFilePath(m_fileName); + + std::lock_guard guard(m_mutex); + + auto const result = doc.load_file(filePath.c_str()); + /* + * Note: status_file_not_found is ok for our use cases: + * - editor: if a user has never made any edits. + * - traffic: if no traffic information has ever been retrieved (first run) + */ + if (result != pugi::status_ok && result != pugi::status_file_not_found) + { + LOG(LERROR, ("Can't load file from disk:", filePath)); + return false; + } + + return true; +} + +bool LocalStorage::Reset() +{ + std::lock_guard guard(m_mutex); + + return base::DeleteFileX(GetFilePath(m_fileName)); +} + +// StorageMemory ----------------------------------------------------------------------------------- +bool InMemoryStorage::Save(pugi::xml_document const & doc) +{ + m_doc.reset(doc); + return true; +} + +bool InMemoryStorage::Load(pugi::xml_document & doc) +{ + doc.reset(m_doc); + return true; +} + +bool InMemoryStorage::Reset() +{ + m_doc.reset(); + return true; +} +} // namespace traffxml diff --git a/traffxml/traff_storage.hpp b/traffxml/traff_storage.hpp new file mode 100644 index 000000000..4cbac8127 --- /dev/null +++ b/traffxml/traff_storage.hpp @@ -0,0 +1,77 @@ +#pragma once + +#include + +#include + +/* + * TODO combine this header and its CPP file with editor/editor_storage.hpp and its CPP counterpart, + * give it an appropriate namespace and place it where both editor and traffic can use it. + * `traff_storage` is essentially copied from `editor_storage` with just a few modifications: + * - namespace + * - instead of relying on a hardcoded file name, `LocalStorage` is initialized with a file name + * - log output, variable names and comments changed to be use case neutral (no API changes) + * - refactoring: no global `using namespace` (no API changes) + * Apart from the first two points, this file can serve as a drop-in replacement for `editor_storage`. + * Traffic uses only `LocalStorage`, the rest has been kept to ease migration to a unified storage + * component. + */ + +namespace traffxml +{ +/** + * @brief Storage interface for XML data. + */ +class StorageBase +{ +public: + virtual ~StorageBase() = default; + + virtual bool Save(pugi::xml_document const & doc) = 0; + virtual bool Load(pugi::xml_document & doc) = 0; + virtual bool Reset() = 0; +}; + +/** + * @brief Class which saves/loads XML data to/from local file. + * @note this class IS thread-safe. + */ +class LocalStorage : public StorageBase +{ +public: + /** + * @brief Constructs a `LocalStorage` instance. + * @param fileName The file name and path where the file in question will be persisted. It is + * interpreted relative to the platform-specific path; absolute paths are not supported as some + * platforms restrict applications’ access to files outside their designated path. + */ + LocalStorage(std::string & fileName) + : m_fileName(fileName) + {} + + // StorageBase overrides: + bool Save(pugi::xml_document const & doc) override; + bool Load(pugi::xml_document & doc) override; + bool Reset() override; + +private: + std::string m_fileName; + std::mutex m_mutex; +}; + +/** + * @brief Class which saves/loads data to/from xml_document class instance. + * @note this class is NOT thread-safe. + */ +class InMemoryStorage : public StorageBase +{ +public: + // StorageBase overrides: + bool Save(pugi::xml_document const & doc) override; + bool Load(pugi::xml_document & doc) override; + bool Reset() override; + +private: + pugi::xml_document m_doc; +}; +} // namespace traffxml