refactor file manager db
This commit is contained in:
parent
f276356172
commit
7567e3289c
87
repertory/librepertory/include/db/i_file_mgr_db.hpp
Normal file
87
repertory/librepertory/include/db/i_file_mgr_db.hpp
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
||||
|
||||
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.
|
||||
*/
|
||||
#ifndef REPERTORY_INCLUDE_DB_I_FILE_MGR_DB_HPP_
|
||||
#define REPERTORY_INCLUDE_DB_I_FILE_MGR_DB_HPP_
|
||||
|
||||
#include "types/repertory.hpp"
|
||||
|
||||
namespace repertory {
|
||||
class i_file_mgr_db {
|
||||
INTERFACE_SETUP(i_file_mgr_db);
|
||||
|
||||
public:
|
||||
struct resume_entry final {
|
||||
std::string api_path;
|
||||
std::uint64_t chunk_size{};
|
||||
boost::dynamic_bitset<> read_state;
|
||||
std::string source_path;
|
||||
};
|
||||
|
||||
struct upload_active_entry final {
|
||||
std::string api_path;
|
||||
std::string source_path;
|
||||
};
|
||||
|
||||
struct upload_entry final {
|
||||
std::string api_path;
|
||||
std::uint64_t date_time{};
|
||||
std::string source_path;
|
||||
};
|
||||
|
||||
public:
|
||||
[[nodiscard]] virtual auto add_resume(resume_entry entry) -> bool = 0;
|
||||
|
||||
[[nodiscard]] virtual auto add_upload(upload_entry entry) -> bool = 0;
|
||||
|
||||
[[nodiscard]] virtual auto
|
||||
add_upload_active(upload_active_entry entry) -> bool = 0;
|
||||
|
||||
virtual void clear() = 0;
|
||||
|
||||
[[nodiscard]] virtual auto
|
||||
get_next_upload() const -> std::optional<upload_entry> = 0;
|
||||
|
||||
[[nodiscard]] virtual auto
|
||||
get_resume_list() const -> std::vector<resume_entry> = 0;
|
||||
|
||||
[[nodiscard]] virtual auto get_upload(const std::string &api_path) const
|
||||
-> std::optional<upload_entry> = 0;
|
||||
|
||||
[[nodiscard]] virtual auto
|
||||
get_upload_active_list() const -> std::vector<upload_active_entry> = 0;
|
||||
|
||||
[[nodiscard]] virtual auto
|
||||
remove_resume(const std::string &api_path) -> bool = 0;
|
||||
|
||||
[[nodiscard]] virtual auto
|
||||
remove_upload(const std::string &api_path) -> bool = 0;
|
||||
|
||||
[[nodiscard]] virtual auto
|
||||
remove_upload_active(const std::string &api_path) -> bool = 0;
|
||||
|
||||
[[nodiscard]] virtual auto
|
||||
rename_resume(const std::string &from_api_path,
|
||||
const std::string &to_api_path) -> bool = 0;
|
||||
};
|
||||
} // namespace repertory
|
||||
|
||||
#endif // REPERTORY_INCLUDE_DB_I_FILE_MGR_DB_HPP_
|
91
repertory/librepertory/include/db/rdb_file_mgr_db.hpp
Normal file
91
repertory/librepertory/include/db/rdb_file_mgr_db.hpp
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
||||
|
||||
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.
|
||||
*/
|
||||
#ifndef REPERTORY_INCLUDE_DB_RDB_FILE_MGR_DB_HPP_
|
||||
#define REPERTORY_INCLUDE_DB_RDB_FILE_MGR_DB_HPP_
|
||||
|
||||
#include "db/i_file_mgr_db.hpp"
|
||||
|
||||
namespace repertory {
|
||||
class app_config;
|
||||
|
||||
class rdb_file_mgr_db final : public i_file_mgr_db {
|
||||
public:
|
||||
rdb_file_mgr_db(const app_config &cfg);
|
||||
~rdb_file_mgr_db() override;
|
||||
|
||||
rdb_file_mgr_db(const rdb_file_mgr_db &) = delete;
|
||||
rdb_file_mgr_db(rdb_file_mgr_db &&) = delete;
|
||||
auto operator=(const rdb_file_mgr_db &) -> rdb_file_mgr_db & = delete;
|
||||
auto operator=(rdb_file_mgr_db &&) -> rdb_file_mgr_db & = delete;
|
||||
|
||||
private:
|
||||
const app_config &cfg_;
|
||||
|
||||
private:
|
||||
std::unique_ptr<rocksdb::DB> db_;
|
||||
std::atomic<std::uint64_t> id_{0U};
|
||||
rocksdb::ColumnFamilyHandle *resume_family_{};
|
||||
rocksdb::ColumnFamilyHandle *upload_active_family_{};
|
||||
rocksdb::ColumnFamilyHandle *upload_family_{};
|
||||
|
||||
private:
|
||||
void create_or_open(bool clear);
|
||||
|
||||
public:
|
||||
[[nodiscard]] auto add_resume(resume_entry entry) -> bool override;
|
||||
|
||||
[[nodiscard]] auto add_upload(upload_entry entry) -> bool override;
|
||||
|
||||
[[nodiscard]] auto
|
||||
add_upload_active(upload_active_entry entry) -> bool override;
|
||||
|
||||
void clear() override;
|
||||
|
||||
[[nodiscard]] auto
|
||||
get_next_upload() const -> std::optional<upload_entry> override;
|
||||
|
||||
[[nodiscard]] auto
|
||||
get_resume_list() const -> std::vector<resume_entry> override;
|
||||
|
||||
[[nodiscard]] auto get_upload(const std::string &api_path) const
|
||||
-> std::optional<upload_entry> override;
|
||||
|
||||
[[nodiscard]] auto
|
||||
get_upload_active_list() const -> std::vector<upload_active_entry> override;
|
||||
|
||||
[[nodiscard]] auto
|
||||
remove_resume(const std::string &api_path) -> bool override;
|
||||
|
||||
[[nodiscard]] auto
|
||||
remove_upload(const std::string &api_path) -> bool override;
|
||||
|
||||
[[nodiscard]] auto
|
||||
remove_upload_active(const std::string &api_path) -> bool override;
|
||||
|
||||
[[nodiscard]] auto
|
||||
rename_resume(const std::string &from_api_path,
|
||||
const std::string &to_api_path) -> bool override;
|
||||
};
|
||||
|
||||
} // namespace repertory
|
||||
|
||||
#endif // REPERTORY_INCLUDE_DB_RDB_FILE_MGR_DB_HPP_
|
82
repertory/librepertory/include/db/sqlite_file_mgr_db.hpp
Normal file
82
repertory/librepertory/include/db/sqlite_file_mgr_db.hpp
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
||||
|
||||
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.
|
||||
*/
|
||||
#ifndef REPERTORY_INCLUDE_DB_SQLITE_FILE_MGR_DB_HPP_
|
||||
#define REPERTORY_INCLUDE_DB_SQLITE_FILE_MGR_DB_HPP_
|
||||
|
||||
#include "db/i_file_mgr_db.hpp"
|
||||
#include "utils/db/sqlite/db_common.hpp"
|
||||
|
||||
namespace repertory {
|
||||
class app_config;
|
||||
|
||||
class sqlite_file_mgr_db final : public i_file_mgr_db {
|
||||
public:
|
||||
sqlite_file_mgr_db(const app_config &cfg);
|
||||
~sqlite_file_mgr_db() override;
|
||||
|
||||
sqlite_file_mgr_db(const sqlite_file_mgr_db &) = delete;
|
||||
sqlite_file_mgr_db(sqlite_file_mgr_db &&) = delete;
|
||||
auto operator=(const sqlite_file_mgr_db &) -> sqlite_file_mgr_db & = delete;
|
||||
auto operator=(sqlite_file_mgr_db &&) -> sqlite_file_mgr_db & = delete;
|
||||
|
||||
private:
|
||||
utils::db::sqlite::db3_t db_;
|
||||
|
||||
public:
|
||||
[[nodiscard]] auto add_resume(resume_entry entry) -> bool override;
|
||||
|
||||
[[nodiscard]] auto add_upload(upload_entry entry) -> bool override;
|
||||
|
||||
[[nodiscard]] auto
|
||||
add_upload_active(upload_active_entry entry) -> bool override;
|
||||
|
||||
void clear() override;
|
||||
|
||||
[[nodiscard]] auto
|
||||
get_next_upload() const -> std::optional<upload_entry> override;
|
||||
|
||||
[[nodiscard]] auto
|
||||
get_resume_list() const -> std::vector<resume_entry> override;
|
||||
|
||||
[[nodiscard]] auto get_upload(const std::string &api_path) const
|
||||
-> std::optional<upload_entry> override;
|
||||
|
||||
[[nodiscard]] auto
|
||||
get_upload_active_list() const -> std::vector<upload_active_entry> override;
|
||||
|
||||
[[nodiscard]] auto
|
||||
remove_resume(const std::string &api_path) -> bool override;
|
||||
|
||||
[[nodiscard]] auto
|
||||
remove_upload(const std::string &api_path) -> bool override;
|
||||
|
||||
[[nodiscard]] auto
|
||||
remove_upload_active(const std::string &api_path) -> bool override;
|
||||
|
||||
[[nodiscard]] auto
|
||||
rename_resume(const std::string &from_api_path,
|
||||
const std::string &to_api_path) -> bool override;
|
||||
};
|
||||
|
||||
} // namespace repertory
|
||||
|
||||
#endif // REPERTORY_INCLUDE_DB_SQLITE_FILE_MGR_DB_HPP_
|
@ -22,15 +22,14 @@
|
||||
#ifndef REPERTORY_INCLUDE_FILE_MANAGER_FILE_MANAGER_HPP_
|
||||
#define REPERTORY_INCLUDE_FILE_MANAGER_FILE_MANAGER_HPP_
|
||||
|
||||
#include "db/i_file_mgr_db.hpp"
|
||||
#include "events/event_system.hpp"
|
||||
#include "events/events.hpp"
|
||||
#include "file_manager/i_file_manager.hpp"
|
||||
#include "file_manager/i_open_file.hpp"
|
||||
#include "file_manager/i_upload_manager.hpp"
|
||||
#include "file_manager/upload.hpp"
|
||||
#include "platform/platform.hpp"
|
||||
#include "types/repertory.hpp"
|
||||
#include "utils/db/sqlite/db_common.hpp"
|
||||
#include "utils/file.hpp"
|
||||
|
||||
namespace repertory {
|
||||
@ -57,7 +56,7 @@ private:
|
||||
i_provider &provider_;
|
||||
|
||||
private:
|
||||
utils::db::sqlite::db3_t db_;
|
||||
std::unique_ptr<i_file_mgr_db> mgr_db_;
|
||||
std::atomic<std::uint64_t> next_handle_{0U};
|
||||
mutable std::recursive_mutex open_file_mtx_;
|
||||
std::unordered_map<std::string, std::shared_ptr<i_closeable_open_file>>
|
||||
@ -132,12 +131,13 @@ public:
|
||||
|
||||
[[nodiscard]] auto get_open_handle_count() const -> std::size_t;
|
||||
|
||||
[[nodiscard]] auto get_stored_downloads() const -> std::vector<json>;
|
||||
[[nodiscard]] auto
|
||||
get_stored_downloads() const -> std::vector<i_file_mgr_db::resume_entry>;
|
||||
|
||||
[[nodiscard]] auto has_no_open_file_handles() const -> bool override;
|
||||
|
||||
[[nodiscard]] auto is_processing(const std::string &api_path) const
|
||||
-> bool override;
|
||||
[[nodiscard]] auto
|
||||
is_processing(const std::string &api_path) const -> bool override;
|
||||
|
||||
#if defined(PROJECT_TESTING)
|
||||
[[nodiscard]] auto open(std::shared_ptr<i_closeable_open_file> of,
|
||||
@ -150,13 +150,13 @@ public:
|
||||
|
||||
[[nodiscard]] auto remove_file(const std::string &api_path) -> api_error;
|
||||
|
||||
[[nodiscard]] auto rename_directory(const std::string &from_api_path,
|
||||
const std::string &to_api_path)
|
||||
-> api_error;
|
||||
[[nodiscard]] auto
|
||||
rename_directory(const std::string &from_api_path,
|
||||
const std::string &to_api_path) -> api_error;
|
||||
|
||||
[[nodiscard]] auto rename_file(const std::string &from_api_path,
|
||||
const std::string &to_api_path, bool overwrite)
|
||||
-> api_error;
|
||||
const std::string &to_api_path,
|
||||
bool overwrite) -> api_error;
|
||||
|
||||
void start();
|
||||
|
||||
|
116
repertory/librepertory/src/db/rdb_file_mgr_db.cpp
Normal file
116
repertory/librepertory/src/db/rdb_file_mgr_db.cpp
Normal file
@ -0,0 +1,116 @@
|
||||
/*
|
||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
||||
|
||||
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 "db/rdb_file_mgr_db.hpp"
|
||||
|
||||
#include "app_config.hpp"
|
||||
#include "types/startup_exception.hpp"
|
||||
#include "utils/config.hpp"
|
||||
#include "utils/error_utils.hpp"
|
||||
#include "utils/file.hpp"
|
||||
#include "utils/path.hpp"
|
||||
#include "utils/string.hpp"
|
||||
|
||||
namespace {
|
||||
[[nodiscard]] auto
|
||||
create_rocksdb(const repertory::app_config &cfg, const std::string &name,
|
||||
const std::vector<rocksdb::ColumnFamilyDescriptor> &families,
|
||||
std::vector<rocksdb::ColumnFamilyHandle *> &handles,
|
||||
bool clear) -> std::unique_ptr<rocksdb::DB> {
|
||||
REPERTORY_USES_FUNCTION_NAME();
|
||||
|
||||
auto path = repertory::utils::path::combine(cfg.get_data_directory(), {name});
|
||||
if (clear &&
|
||||
not repertory::utils::file::directory{path}.remove_recursively()) {
|
||||
repertory::utils::error::raise_error(
|
||||
function_name, "failed to remove file mgr db|" + path);
|
||||
}
|
||||
|
||||
rocksdb::Options options{};
|
||||
options.create_if_missing = true;
|
||||
options.create_missing_column_families = true;
|
||||
options.db_log_dir = cfg.get_log_directory();
|
||||
options.keep_log_file_num = 10;
|
||||
|
||||
rocksdb::DB *ptr{};
|
||||
auto status = rocksdb::DB::Open(options, path, families, &handles, &ptr);
|
||||
if (not status.ok()) {
|
||||
repertory::utils::error::raise_error(function_name, status.ToString());
|
||||
throw repertory::startup_exception(status.ToString());
|
||||
}
|
||||
|
||||
return std::unique_ptr<rocksdb::DB>(ptr);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace repertory {
|
||||
rdb_file_mgr_db::rdb_file_mgr_db(const app_config &cfg) : cfg_(cfg) {
|
||||
create_or_open(false);
|
||||
}
|
||||
|
||||
rdb_file_mgr_db::~rdb_file_mgr_db() { db_.reset(); }
|
||||
|
||||
void rdb_file_mgr_db::create_or_open(bool clear) {
|
||||
db_.reset();
|
||||
|
||||
auto families = std::vector<rocksdb::ColumnFamilyDescriptor>();
|
||||
families.emplace_back(rocksdb::kDefaultColumnFamilyName,
|
||||
rocksdb::ColumnFamilyOptions());
|
||||
families.emplace_back("upload_active", rocksdb::ColumnFamilyOptions());
|
||||
families.emplace_back("upload", rocksdb::ColumnFamilyOptions());
|
||||
|
||||
auto handles = std::vector<rocksdb::ColumnFamilyHandle *>();
|
||||
db_ = create_rocksdb(cfg_, "mgr", families, handles, clear);
|
||||
|
||||
std::size_t idx{};
|
||||
resume_family_ = handles[idx++];
|
||||
upload_active_family_ = handles[idx++];
|
||||
upload_family_ = handles[idx++];
|
||||
}
|
||||
|
||||
auto rdb_file_mgr_db::add_resume(resume_entry entry) -> bool {}
|
||||
|
||||
auto rdb_file_mgr_db::add_upload(upload_entry entry) -> bool {}
|
||||
|
||||
auto rdb_file_mgr_db::add_upload_active(upload_active_entry entry) -> bool {}
|
||||
|
||||
void rdb_file_mgr_db::clear() {}
|
||||
|
||||
auto rdb_file_mgr_db::get_next_upload() const -> std::optional<upload_entry> {}
|
||||
|
||||
auto rdb_file_mgr_db::get_resume_list() const -> std::vector<resume_entry> {}
|
||||
|
||||
auto rdb_file_mgr_db::get_upload(const std::string &api_path) const
|
||||
-> std::optional<upload_entry> {}
|
||||
|
||||
auto rdb_file_mgr_db::get_upload_active_list() const
|
||||
-> std::vector<upload_active_entry> {}
|
||||
|
||||
auto rdb_file_mgr_db::remove_resume(const std::string &api_path) -> bool {}
|
||||
|
||||
auto rdb_file_mgr_db::remove_upload(const std::string &api_path) -> bool {}
|
||||
|
||||
auto rdb_file_mgr_db::remove_upload_active(const std::string &api_path)
|
||||
-> bool {}
|
||||
|
||||
auto rdb_file_mgr_db::rename_resume(const std::string &from_api_path,
|
||||
const std::string &to_api_path) -> bool {}
|
||||
} // namespace repertory
|
274
repertory/librepertory/src/db/sqlite_file_mgr_db.cpp
Normal file
274
repertory/librepertory/src/db/sqlite_file_mgr_db.cpp
Normal file
@ -0,0 +1,274 @@
|
||||
/*
|
||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
||||
|
||||
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 "db/sqlite_file_mgr_db.hpp"
|
||||
|
||||
#include "app_config.hpp"
|
||||
#include "utils/config.hpp"
|
||||
#include "utils/db/sqlite/db_common.hpp"
|
||||
#include "utils/db/sqlite/db_delete.hpp"
|
||||
#include "utils/db/sqlite/db_insert.hpp"
|
||||
#include "utils/db/sqlite/db_select.hpp"
|
||||
#include "utils/db/sqlite/db_update.hpp"
|
||||
#include "utils/error_utils.hpp"
|
||||
#include "utils/path.hpp"
|
||||
#include "utils/string.hpp"
|
||||
|
||||
namespace {
|
||||
const std::string resume_table = "resume";
|
||||
const std::string upload_table = "upload";
|
||||
const std::string upload_active_table = "upload_active";
|
||||
const std::map<std::string, std::string> sql_create_tables{
|
||||
{
|
||||
{resume_table},
|
||||
{
|
||||
"CREATE TABLE IF NOT EXISTS " + resume_table +
|
||||
"("
|
||||
"api_path TEXT PRIMARY KEY ASC, "
|
||||
"chunk_size INTEGER, "
|
||||
"read_state TEXT, "
|
||||
"source_path TEXT"
|
||||
");",
|
||||
},
|
||||
},
|
||||
{
|
||||
{upload_table},
|
||||
{
|
||||
"CREATE TABLE IF NOT EXISTS " + upload_table +
|
||||
"("
|
||||
"id INTEGER PRIMARY KEY AUTOINCREMENT, "
|
||||
"api_path TEXT UNIQUE, "
|
||||
"date_time INTEGER, "
|
||||
"source_path TEXT"
|
||||
");",
|
||||
},
|
||||
},
|
||||
{
|
||||
{upload_active_table},
|
||||
{
|
||||
"CREATE TABLE IF NOT EXISTS " + upload_active_table +
|
||||
"("
|
||||
"api_path TEXT PRIMARY KEY ASC, "
|
||||
"source_path TEXT"
|
||||
");",
|
||||
},
|
||||
},
|
||||
};
|
||||
} // namespace
|
||||
|
||||
namespace repertory {
|
||||
sqlite_file_mgr_db::sqlite_file_mgr_db(const app_config &cfg) {
|
||||
db_ = utils::db::sqlite::create_db(
|
||||
utils::path::combine(cfg.get_data_directory(), {"mgr.db"}),
|
||||
sql_create_tables);
|
||||
}
|
||||
|
||||
sqlite_file_mgr_db::~sqlite_file_mgr_db() { db_.reset(); }
|
||||
|
||||
auto sqlite_file_mgr_db::add_resume(resume_entry entry) -> bool {
|
||||
return utils::db::sqlite::db_insert{*db_, resume_table}
|
||||
.or_replace()
|
||||
.column_value("api_path", entry.api_path)
|
||||
.column_value("chunk_size", static_cast<std::int64_t>(entry.chunk_size))
|
||||
.column_value("read_state",
|
||||
utils::string::from_dynamic_bitset(entry.read_state))
|
||||
.column_value("source_path", entry.source_path)
|
||||
.go()
|
||||
.ok();
|
||||
}
|
||||
|
||||
auto sqlite_file_mgr_db::add_upload(upload_entry entry) -> bool {
|
||||
return utils::db::sqlite::db_insert{*db_, upload_table}
|
||||
.or_replace()
|
||||
.column_value("api_path", entry.api_path)
|
||||
.column_value("date_time", static_cast<std::int64_t>(entry.date_time))
|
||||
.column_value("source_path", entry.source_path)
|
||||
.go()
|
||||
.ok();
|
||||
}
|
||||
|
||||
auto sqlite_file_mgr_db::add_upload_active(upload_active_entry entry) -> bool {
|
||||
return utils::db::sqlite::db_insert{*db_, upload_table}
|
||||
.or_replace()
|
||||
.column_value("api_path", entry.api_path)
|
||||
.column_value("source_path", entry.source_path)
|
||||
.go()
|
||||
.ok();
|
||||
}
|
||||
|
||||
void sqlite_file_mgr_db::clear() {
|
||||
REPERTORY_USES_FUNCTION_NAME();
|
||||
|
||||
auto result = utils::db::sqlite::db_delete{*db_, resume_table}.go();
|
||||
if (not result.ok()) {
|
||||
utils::error::raise_error(function_name,
|
||||
"failed to clear resume table|" +
|
||||
std::to_string(result.get_error()));
|
||||
}
|
||||
|
||||
result = utils::db::sqlite::db_delete{*db_, upload_active_table}.go();
|
||||
if (not result.ok()) {
|
||||
utils::error::raise_error(function_name,
|
||||
"failed to clear upload active table|" +
|
||||
std::to_string(result.get_error()));
|
||||
}
|
||||
|
||||
result = utils::db::sqlite::db_delete{*db_, upload_table}.go();
|
||||
if (not result.ok()) {
|
||||
utils::error::raise_error(function_name,
|
||||
"failed to clear upload table|" +
|
||||
std::to_string(result.get_error()));
|
||||
}
|
||||
}
|
||||
|
||||
auto sqlite_file_mgr_db::get_next_upload() const
|
||||
-> std::optional<upload_entry> {
|
||||
auto result = utils::db::sqlite::db_select{*db_, upload_table}
|
||||
.order_by("id", true)
|
||||
.limit(1)
|
||||
.go();
|
||||
std::optional<utils::db::sqlite::db_result::row> row;
|
||||
if (not result.get_row(row) || not row.has_value()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return upload_entry{
|
||||
row->get_column("api_path").get_value<std::string>(),
|
||||
static_cast<std::uint64_t>(
|
||||
row->get_column("date_time").get_value<std::int64_t>()),
|
||||
row->get_column("source_path").get_value<std::string>(),
|
||||
};
|
||||
}
|
||||
|
||||
auto sqlite_file_mgr_db::get_resume_list() const -> std::vector<resume_entry> {
|
||||
REPERTORY_USES_FUNCTION_NAME();
|
||||
|
||||
std::vector<resume_entry> ret;
|
||||
auto result = utils::db::sqlite::db_select{*db_, resume_table}.go();
|
||||
while (result.has_row()) {
|
||||
try {
|
||||
std::optional<utils::db::sqlite::db_result::row> row;
|
||||
if (not result.get_row(row)) {
|
||||
continue;
|
||||
}
|
||||
if (not row.has_value()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ret.push_back(resume_entry{
|
||||
row->get_column("api_path").get_value<std::string>(),
|
||||
static_cast<std::uint64_t>(
|
||||
row->get_column("chunk_size").get_value<std::int64_t>()),
|
||||
utils::string::to_dynamic_bitset(
|
||||
row->get_column("read_state").get_value<std::string>()),
|
||||
row->get_column("source_path").get_value<std::string>(),
|
||||
});
|
||||
} catch (const std::exception &ex) {
|
||||
utils::error::raise_error(function_name, ex, "query error");
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
auto sqlite_file_mgr_db::get_upload(const std::string &api_path) const
|
||||
-> std::optional<upload_entry> {
|
||||
auto result = utils::db::sqlite::db_select{*db_, upload_table}
|
||||
.column("source_path")
|
||||
.where("api_path")
|
||||
.equals(api_path)
|
||||
.go();
|
||||
std::optional<utils::db::sqlite::db_result::row> row;
|
||||
if (not result.get_row(row) || not row.has_value()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return upload_entry{
|
||||
row->get_column("api_path").get_value<std::string>(),
|
||||
static_cast<std::uint64_t>(
|
||||
row->get_column("date_time").get_value<std::int64_t>()),
|
||||
row->get_column("source_path").get_value<std::string>(),
|
||||
};
|
||||
}
|
||||
|
||||
auto sqlite_file_mgr_db::get_upload_active_list() const
|
||||
-> std::vector<upload_active_entry> {
|
||||
REPERTORY_USES_FUNCTION_NAME();
|
||||
|
||||
std::vector<upload_active_entry> ret;
|
||||
auto result = utils::db::sqlite::db_select{*db_, upload_active_table}.go();
|
||||
while (result.has_row()) {
|
||||
try {
|
||||
std::optional<utils::db::sqlite::db_result::row> row;
|
||||
if (not result.get_row(row)) {
|
||||
continue;
|
||||
}
|
||||
if (not row.has_value()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ret.push_back(upload_active_entry{
|
||||
row->get_column("api_path").get_value<std::string>(),
|
||||
row->get_column("source_path").get_value<std::string>(),
|
||||
});
|
||||
} catch (const std::exception &ex) {
|
||||
utils::error::raise_error(function_name, ex, "query error");
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
auto sqlite_file_mgr_db::remove_resume(const std::string &api_path) -> bool {
|
||||
return utils::db::sqlite::db_delete{*db_, resume_table}
|
||||
.where("api_path")
|
||||
.equals(api_path)
|
||||
.go()
|
||||
.ok();
|
||||
}
|
||||
|
||||
auto sqlite_file_mgr_db::remove_upload(const std::string &api_path) -> bool {
|
||||
return utils::db::sqlite::db_delete{*db_, upload_table}
|
||||
.where("api_path")
|
||||
.equals(api_path)
|
||||
.go()
|
||||
.ok();
|
||||
}
|
||||
|
||||
auto sqlite_file_mgr_db::remove_upload_active(const std::string &api_path)
|
||||
-> bool {
|
||||
return utils::db::sqlite::db_delete{*db_, upload_active_table}
|
||||
.where("api_path")
|
||||
.equals(api_path)
|
||||
.go()
|
||||
.ok();
|
||||
}
|
||||
|
||||
auto sqlite_file_mgr_db::rename_resume(const std::string &from_api_path,
|
||||
const std::string &to_api_path) -> bool {
|
||||
return utils::db::sqlite::db_update{*db_, resume_table}
|
||||
.column_value("api_path", to_api_path)
|
||||
.where("api_path")
|
||||
.equals(from_api_path)
|
||||
.go()
|
||||
.ok();
|
||||
}
|
||||
} // namespace repertory
|
@ -64,7 +64,8 @@ void sqlite_meta_db::clear() {
|
||||
}
|
||||
|
||||
utils::error::raise_error(function_name,
|
||||
"failed to clear meta db|" + result.get_error());
|
||||
"failed to clear meta db|" +
|
||||
std::to_string(result.get_error()));
|
||||
}
|
||||
|
||||
auto sqlite_meta_db::get_api_path(const std::string &source_path,
|
||||
|
@ -22,19 +22,16 @@
|
||||
#include "file_manager/file_manager.hpp"
|
||||
|
||||
#include "app_config.hpp"
|
||||
#include "db/sqlite_file_mgr_db.hpp"
|
||||
#include "file_manager/events.hpp"
|
||||
#include "file_manager/open_file.hpp"
|
||||
#include "file_manager/open_file_base.hpp"
|
||||
#include "file_manager/ring_buffer_open_file.hpp"
|
||||
#include "file_manager/upload.hpp"
|
||||
#include "platform/platform.hpp"
|
||||
#include "providers/i_provider.hpp"
|
||||
#include "types/repertory.hpp"
|
||||
#include "utils/common.hpp"
|
||||
#include "utils/db/sqlite/db_common.hpp"
|
||||
#include "utils/db/sqlite/db_delete.hpp"
|
||||
#include "utils/db/sqlite/db_insert.hpp"
|
||||
#include "utils/db/sqlite/db_select.hpp"
|
||||
#include "utils/db/sqlite/db_update.hpp"
|
||||
#include "utils/encrypting_reader.hpp"
|
||||
#include "utils/error_utils.hpp"
|
||||
#include "utils/file.hpp"
|
||||
@ -42,85 +39,24 @@
|
||||
#include "utils/polling.hpp"
|
||||
#include "utils/time.hpp"
|
||||
|
||||
namespace {
|
||||
[[nodiscard]] auto
|
||||
create_resume_entry(const repertory::i_open_file &file) -> json {
|
||||
return {
|
||||
{"chunk_size", file.get_chunk_size()},
|
||||
{"path", file.get_api_path()},
|
||||
{"read_state",
|
||||
repertory::utils::string::from_dynamic_bitset(file.get_read_state())},
|
||||
{"source", file.get_source_path()},
|
||||
};
|
||||
}
|
||||
|
||||
void restore_resume_entry(const json &resume_entry, std::string &api_path,
|
||||
std::size_t &chunk_size,
|
||||
boost::dynamic_bitset<> &read_state,
|
||||
std::string &source_path) {
|
||||
api_path = resume_entry["path"].get<std::string>();
|
||||
chunk_size = resume_entry["chunk_size"].get<std::size_t>();
|
||||
read_state = repertory::utils::string::to_dynamic_bitset(
|
||||
resume_entry["read_state"].get<std::string>());
|
||||
source_path = resume_entry["source"].get<std::string>();
|
||||
}
|
||||
|
||||
const std::string resume_table = "resume";
|
||||
const std::string upload_table = "upload";
|
||||
const std::string upload_active_table = "upload_active";
|
||||
const std::map<std::string, std::string> sql_create_tables{
|
||||
{
|
||||
{resume_table},
|
||||
{
|
||||
"CREATE TABLE IF NOT EXISTS " + resume_table +
|
||||
"("
|
||||
"api_path TEXT PRIMARY KEY ASC, "
|
||||
"data TEXT"
|
||||
");",
|
||||
},
|
||||
},
|
||||
{
|
||||
{upload_table},
|
||||
{
|
||||
"CREATE TABLE IF NOT EXISTS " + upload_table +
|
||||
"("
|
||||
"api_path TEXT PRIMARY KEY ASC, "
|
||||
"date_time INTEGER, "
|
||||
"source_path TEXT"
|
||||
");",
|
||||
},
|
||||
},
|
||||
{
|
||||
{upload_active_table},
|
||||
{
|
||||
"CREATE TABLE IF NOT EXISTS " + upload_active_table +
|
||||
"("
|
||||
"api_path TEXT PRIMARY KEY ASC, "
|
||||
"source_path TEXT"
|
||||
");",
|
||||
},
|
||||
},
|
||||
};
|
||||
} // namespace
|
||||
|
||||
namespace repertory {
|
||||
file_manager::file_manager(app_config &config, i_provider &provider)
|
||||
: config_(config), provider_(provider) {
|
||||
db_ = utils::db::sqlite::create_db(
|
||||
utils::path::combine(config_.get_data_directory(), {"file_manager.db"}),
|
||||
sql_create_tables);
|
||||
mgr_db_ = std::make_unique<sqlite_file_mgr_db>(config_);
|
||||
|
||||
if (not provider_.is_read_only()) {
|
||||
E_SUBSCRIBE_EXACT(file_upload_completed,
|
||||
[this](const file_upload_completed &completed) {
|
||||
this->upload_completed(completed);
|
||||
});
|
||||
if (provider_.is_read_only()) {
|
||||
return;
|
||||
}
|
||||
|
||||
E_SUBSCRIBE_EXACT(file_upload_completed,
|
||||
[this](const file_upload_completed &completed) {
|
||||
this->upload_completed(completed);
|
||||
});
|
||||
}
|
||||
|
||||
file_manager::~file_manager() {
|
||||
stop();
|
||||
db_.reset();
|
||||
mgr_db_.reset();
|
||||
|
||||
E_CONSUMER_RELEASE();
|
||||
}
|
||||
@ -336,32 +272,15 @@ auto file_manager::get_open_handle_count() const -> std::size_t {
|
||||
});
|
||||
}
|
||||
|
||||
auto file_manager::get_stored_downloads() const -> std::vector<json> {
|
||||
auto file_manager::get_stored_downloads() const
|
||||
-> std::vector<i_file_mgr_db::resume_entry> {
|
||||
REPERTORY_USES_FUNCTION_NAME();
|
||||
|
||||
if (provider_.is_read_only()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<json> ret;
|
||||
auto result = utils::db::sqlite::db_select{*db_, resume_table}.go();
|
||||
while (result.has_row()) {
|
||||
try {
|
||||
std::optional<utils::db::sqlite::db_result::row> row;
|
||||
if (not result.get_row(row)) {
|
||||
continue;
|
||||
}
|
||||
if (not row.has_value()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ret.push_back(row.value().get_column("data").get_value_as_json());
|
||||
} catch (const std::exception &ex) {
|
||||
utils::error::raise_error(function_name, ex, "query error");
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
return mgr_db_->get_resume_list();
|
||||
}
|
||||
|
||||
auto file_manager::handle_file_rename(const std::string &from_api_path,
|
||||
@ -379,15 +298,10 @@ auto file_manager::handle_file_rename(const std::string &from_api_path,
|
||||
source_path = upload_lookup_.at(from_api_path)->get_source_path();
|
||||
}
|
||||
} else {
|
||||
auto result = utils::db::sqlite::db_select{*db_, upload_table}
|
||||
.column("source_path")
|
||||
.where("api_path")
|
||||
.equals(from_api_path)
|
||||
.go();
|
||||
std::optional<utils::db::sqlite::db_result::row> row;
|
||||
should_upload = result.get_row(row) && row.has_value();
|
||||
auto upload = mgr_db_->get_upload(from_api_path);
|
||||
should_upload = upload.has_value();
|
||||
if (should_upload && source_path.empty()) {
|
||||
source_path = row->get_column("source_path").get_value<std::string>();
|
||||
source_path = upload->source_path;
|
||||
}
|
||||
}
|
||||
|
||||
@ -427,8 +341,8 @@ auto file_manager::is_processing(const std::string &api_path) const -> bool {
|
||||
}
|
||||
upload_lock.unlock();
|
||||
|
||||
utils::db::sqlite::db_select query{*db_, upload_table};
|
||||
if (query.where("api_path").equals(api_path).go().has_row()) {
|
||||
auto upload = mgr_db_->get_upload(api_path);
|
||||
if (upload.has_value()) {
|
||||
return true;
|
||||
};
|
||||
|
||||
@ -510,21 +424,16 @@ void file_manager::queue_upload(const std::string &api_path,
|
||||
|
||||
remove_upload(api_path, true);
|
||||
|
||||
auto result =
|
||||
utils::db::sqlite::db_insert{*db_, upload_table}
|
||||
.or_replace()
|
||||
.column_value("api_path", api_path)
|
||||
.column_value("date_time",
|
||||
static_cast<std::int64_t>(utils::time::get_time_now()))
|
||||
.column_value("source_path", source_path)
|
||||
.go();
|
||||
if (result.ok()) {
|
||||
if (mgr_db_->add_upload({
|
||||
api_path,
|
||||
utils::time::get_time_now(),
|
||||
source_path,
|
||||
})) {
|
||||
remove_resume(api_path, source_path);
|
||||
event_system::instance().raise<file_upload_queued>(api_path, source_path);
|
||||
} else {
|
||||
event_system::instance().raise<file_upload_failed>(
|
||||
api_path, source_path,
|
||||
std::to_string(result.get_error()) + '|' + result.get_error_str());
|
||||
api_path, source_path, "failed to queue upload");
|
||||
}
|
||||
|
||||
if (not no_lock) {
|
||||
@ -561,14 +470,12 @@ auto file_manager::remove_file(const std::string &api_path) -> api_error {
|
||||
|
||||
void file_manager::remove_resume(const std::string &api_path,
|
||||
const std::string &source_path) {
|
||||
auto result = utils::db::sqlite::db_delete{*db_, resume_table}
|
||||
.where("api_path")
|
||||
.equals(api_path)
|
||||
.go();
|
||||
if (result.ok()) {
|
||||
event_system::instance().raise<download_resume_removed>(api_path,
|
||||
source_path);
|
||||
if (not mgr_db_->remove_resume(api_path)) {
|
||||
return;
|
||||
}
|
||||
|
||||
event_system::instance().raise<download_resume_removed>(api_path,
|
||||
source_path);
|
||||
}
|
||||
|
||||
void file_manager::remove_upload(const std::string &api_path) {
|
||||
@ -587,21 +494,13 @@ void file_manager::remove_upload(const std::string &api_path, bool no_lock) {
|
||||
lock = std::make_unique<mutex_lock>(upload_mtx_);
|
||||
}
|
||||
|
||||
auto result = utils::db::sqlite::db_delete{*db_, upload_table}
|
||||
.where("api_path")
|
||||
.equals(api_path)
|
||||
.go();
|
||||
if (not result.ok()) {
|
||||
utils::error::raise_api_path_error(function_name, api_path,
|
||||
api_error::error,
|
||||
"failed to remove from upload table");
|
||||
if (not mgr_db_->remove_upload(api_path)) {
|
||||
utils::error::raise_api_path_error(
|
||||
function_name, api_path, api_error::error, "failed to remove upload");
|
||||
}
|
||||
|
||||
result = utils::db::sqlite::db_delete{*db_, upload_active_table}
|
||||
.where("api_path")
|
||||
.equals(api_path)
|
||||
.go();
|
||||
if (not result.ok()) {
|
||||
auto removed = not mgr_db_->remove_upload_active(api_path);
|
||||
if (not removed) {
|
||||
utils::error::raise_api_path_error(
|
||||
function_name, api_path, api_error::error,
|
||||
"failed to remove from upload_active table");
|
||||
@ -612,7 +511,7 @@ void file_manager::remove_upload(const std::string &api_path, bool no_lock) {
|
||||
upload_lookup_.erase(api_path);
|
||||
}
|
||||
|
||||
if (result.ok()) {
|
||||
if (removed) {
|
||||
event_system::instance().raise<file_upload_removed>(api_path);
|
||||
}
|
||||
|
||||
@ -779,15 +678,6 @@ void file_manager::start() {
|
||||
|
||||
stop_requested_ = false;
|
||||
|
||||
polling::instance().set_callback({
|
||||
"db_cleanup",
|
||||
polling::frequency::medium,
|
||||
[this](auto && /* stop_requested */) {
|
||||
mutex_lock lock(upload_mtx_);
|
||||
sqlite3_db_release_memory(db_.get());
|
||||
},
|
||||
});
|
||||
|
||||
polling::instance().set_callback({
|
||||
"timed_out_close",
|
||||
polling::frequency::second,
|
||||
@ -799,67 +689,25 @@ void file_manager::start() {
|
||||
return;
|
||||
}
|
||||
|
||||
struct active_item final {
|
||||
std::string api_path;
|
||||
std::string source_path;
|
||||
};
|
||||
for (const auto &entry : mgr_db_->get_upload_active_list()) {
|
||||
queue_upload(entry.api_path, entry.source_path, false);
|
||||
}
|
||||
|
||||
std::vector<active_item> active_items{};
|
||||
|
||||
auto result = utils::db::sqlite::db_select{*db_, upload_active_table}.go();
|
||||
while (result.has_row()) {
|
||||
for (const auto &entry : mgr_db_->get_resume_list()) {
|
||||
try {
|
||||
std::optional<utils::db::sqlite::db_result::row> row;
|
||||
if (result.get_row(row) && row.has_value()) {
|
||||
active_items.emplace_back(active_item{
|
||||
row->get_column("api_path").get_value<std::string>(),
|
||||
row->get_column("source_path").get_value<std::string>(),
|
||||
});
|
||||
}
|
||||
} catch (const std::exception &ex) {
|
||||
utils::error::raise_error(function_name, ex, "query error");
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &&active_item : active_items) {
|
||||
queue_upload(active_item.api_path, active_item.source_path, false);
|
||||
}
|
||||
active_items.clear();
|
||||
|
||||
result = utils::db::sqlite::db_select{*db_, resume_table}.go();
|
||||
if (not result.ok()) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (result.has_row()) {
|
||||
try {
|
||||
std::optional<utils::db::sqlite::db_result::row> row;
|
||||
if (not(result.get_row(row) && row.has_value())) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto resume_entry = row.value().get_column("data").get_value_as_json();
|
||||
|
||||
std::string api_path;
|
||||
std::string source_path;
|
||||
std::size_t chunk_size{};
|
||||
boost::dynamic_bitset<> read_state;
|
||||
restore_resume_entry(resume_entry, api_path, chunk_size, read_state,
|
||||
source_path);
|
||||
|
||||
filesystem_item fsi{};
|
||||
auto res = provider_.get_filesystem_item(api_path, false, fsi);
|
||||
auto res = provider_.get_filesystem_item(entry.api_path, false, fsi);
|
||||
if (res != api_error::success) {
|
||||
event_system::instance().raise<download_restore_failed>(
|
||||
api_path, source_path,
|
||||
entry.api_path, entry.source_path,
|
||||
"failed to get filesystem item|" + api_error_to_string(res));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (source_path != fsi.source_path) {
|
||||
if (entry.source_path != fsi.source_path) {
|
||||
event_system::instance().raise<download_restore_failed>(
|
||||
fsi.api_path, fsi.source_path,
|
||||
"source path mismatch|expected|" + source_path + "|actual|" +
|
||||
"source path mismatch|expected|" + entry.source_path + "|actual|" +
|
||||
fsi.source_path);
|
||||
continue;
|
||||
}
|
||||
@ -883,12 +731,12 @@ void file_manager::start() {
|
||||
}
|
||||
|
||||
auto closeable_file = std::make_shared<open_file>(
|
||||
chunk_size,
|
||||
entry.chunk_size,
|
||||
config_.get_enable_chunk_download_timeout()
|
||||
? config_.get_chunk_downloader_timeout_secs()
|
||||
: 0U,
|
||||
fsi, provider_, read_state, *this);
|
||||
open_file_lookup_[api_path] = closeable_file;
|
||||
fsi, provider_, entry.read_state, *this);
|
||||
open_file_lookup_[entry.api_path] = closeable_file;
|
||||
event_system::instance().raise<download_restored>(fsi.api_path,
|
||||
fsi.source_path);
|
||||
} catch (const std::exception &ex) {
|
||||
@ -948,21 +796,19 @@ void file_manager::store_resume(const i_open_file &file) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto result = utils::db::sqlite::db_insert{*db_, resume_table}
|
||||
.or_replace()
|
||||
.column_value("api_path", file.get_api_path())
|
||||
.column_value("data", create_resume_entry(file).dump())
|
||||
.go();
|
||||
if (result.ok()) {
|
||||
if (mgr_db_->add_resume({
|
||||
file.get_api_path(),
|
||||
file.get_chunk_size(),
|
||||
file.get_read_state(),
|
||||
file.get_source_path(),
|
||||
})) {
|
||||
event_system::instance().raise<download_resume_added>(
|
||||
file.get_api_path(), file.get_source_path());
|
||||
return;
|
||||
}
|
||||
|
||||
event_system::instance().raise<download_resume_add_failed>(
|
||||
file.get_api_path(), file.get_source_path(),
|
||||
"failed to insert|" + std::to_string(result.get_error()) + '|' +
|
||||
result.get_error_str());
|
||||
file.get_api_path(), file.get_source_path(), "failed to store resume");
|
||||
}
|
||||
|
||||
void file_manager::swap_renamed_items(std::string from_api_path,
|
||||
@ -981,16 +827,13 @@ void file_manager::swap_renamed_items(std::string from_api_path,
|
||||
return;
|
||||
}
|
||||
|
||||
auto result = utils::db::sqlite::db_update{*db_, resume_table}
|
||||
.column_value("api_path", to_api_path)
|
||||
.where("api_path")
|
||||
.equals(from_api_path)
|
||||
.go();
|
||||
if (not result.ok()) {
|
||||
utils::error::raise_api_path_error(function_name, to_api_path,
|
||||
api_error::error,
|
||||
"failed to update resume table");
|
||||
if (mgr_db_->rename_resume(from_api_path, to_api_path)) {
|
||||
return;
|
||||
}
|
||||
|
||||
utils::error::raise_api_path_error(function_name, to_api_path,
|
||||
api_error::error,
|
||||
"failed to update resume table");
|
||||
}
|
||||
|
||||
void file_manager::upload_completed(const file_upload_completed &evt) {
|
||||
@ -1001,11 +844,8 @@ void file_manager::upload_completed(const file_upload_completed &evt) {
|
||||
if (not utils::string::to_bool(evt.get_cancelled().get<std::string>())) {
|
||||
auto err = api_error_from_string(evt.get_result().get<std::string>());
|
||||
if (err == api_error::success) {
|
||||
auto result = utils::db::sqlite::db_delete{*db_, upload_active_table}
|
||||
.where("api_path")
|
||||
.equals(evt.get_api_path().get<std::string>())
|
||||
.go();
|
||||
if (not result.ok()) {
|
||||
if (not mgr_db_->remove_upload_active(
|
||||
evt.get_api_path().get<std::string>())) {
|
||||
utils::error::raise_api_path_error(
|
||||
function_name, evt.get_api_path().get<std::string>(),
|
||||
evt.get_source().get<std::string>(),
|
||||
@ -1046,25 +886,17 @@ void file_manager::upload_handler() {
|
||||
}
|
||||
|
||||
if (upload_lookup_.size() < config_.get_max_upload_count()) {
|
||||
auto result = utils::db::sqlite::db_select{*db_, upload_table}
|
||||
.order_by("api_path", true)
|
||||
.limit(1)
|
||||
.go();
|
||||
try {
|
||||
std::optional<utils::db::sqlite::db_result::row> row;
|
||||
if (result.get_row(row) && row.has_value()) {
|
||||
auto api_path = row->get_column("api_path").get_value<std::string>();
|
||||
auto source_path =
|
||||
row->get_column("source_path").get_value<std::string>();
|
||||
|
||||
auto entry = mgr_db_->get_next_upload();
|
||||
if (entry.has_value()) {
|
||||
filesystem_item fsi{};
|
||||
auto res = provider_.get_filesystem_item(api_path, false, fsi);
|
||||
auto res = provider_.get_filesystem_item(entry->api_path, false, fsi);
|
||||
switch (res) {
|
||||
case api_error::item_not_found: {
|
||||
should_wait = false;
|
||||
event_system::instance().raise<file_upload_not_found>(api_path,
|
||||
source_path);
|
||||
remove_upload(api_path, true);
|
||||
event_system::instance().raise<file_upload_not_found>(
|
||||
entry->api_path, entry->source_path);
|
||||
remove_upload(entry->api_path, true);
|
||||
} break;
|
||||
|
||||
case api_error::success: {
|
||||
@ -1072,28 +904,22 @@ void file_manager::upload_handler() {
|
||||
|
||||
upload_lookup_[fsi.api_path] =
|
||||
std::make_unique<upload>(fsi, provider_);
|
||||
auto del_res = utils::db::sqlite::db_delete{*db_, upload_table}
|
||||
.where("api_path")
|
||||
.equals(api_path)
|
||||
.go();
|
||||
if (del_res.ok()) {
|
||||
auto ins_res =
|
||||
utils::db::sqlite::db_insert{*db_, upload_active_table}
|
||||
.column_value("api_path", api_path)
|
||||
.column_value("source_path", source_path)
|
||||
.go();
|
||||
if (not ins_res.ok()) {
|
||||
if (mgr_db_->remove_upload(entry->api_path)) {
|
||||
if (not mgr_db_->add_upload_active({
|
||||
entry->api_path,
|
||||
entry->source_path,
|
||||
})) {
|
||||
utils::error::raise_api_path_error(
|
||||
function_name, api_path, source_path,
|
||||
function_name, entry->api_path, entry->source_path,
|
||||
"failed to add to upload_active table");
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
default: {
|
||||
event_system::instance().raise<file_upload_retry>(api_path,
|
||||
source_path, res);
|
||||
queue_upload(api_path, source_path, true);
|
||||
event_system::instance().raise<file_upload_retry>(
|
||||
entry->api_path, entry->source_path, res);
|
||||
queue_upload(entry->api_path, entry->source_path, true);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,72 @@
|
||||
/*
|
||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
||||
|
||||
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.
|
||||
*/
|
||||
#ifndef REPERTORY_TEST_INCLUDE_FIXTURES_FILE_MGR_DB_FIXTURE_HPP
|
||||
#define REPERTORY_TEST_INCLUDE_FIXTURES_FILE_MGR_DB_FIXTURE_HPP
|
||||
|
||||
#include "test_common.hpp"
|
||||
|
||||
#include "app_config.hpp"
|
||||
// #include "db/rdb_meta_db.hpp"
|
||||
#include "db/sqlite_file_mgr_db.hpp"
|
||||
#include "events/consumers/console_consumer.hpp"
|
||||
#include "events/event_system.hpp"
|
||||
|
||||
namespace repertory {
|
||||
template <typename db_t> class file_mgr_db_test : public ::testing::Test {
|
||||
protected:
|
||||
static std::unique_ptr<app_config> config;
|
||||
static console_consumer console_;
|
||||
static std::unique_ptr<db_t> file_mgr_db;
|
||||
|
||||
protected:
|
||||
static void SetUpTestCase() {
|
||||
static std::uint64_t idx{};
|
||||
|
||||
event_system::instance().start();
|
||||
auto cfg_directory = utils::path::combine(test::get_test_output_dir(),
|
||||
{
|
||||
"file_mgr_db_test",
|
||||
std::to_string(++idx),
|
||||
});
|
||||
config = std::make_unique<app_config>(provider_type::s3, cfg_directory);
|
||||
file_mgr_db = std::make_unique<db_t>(*config);
|
||||
}
|
||||
|
||||
static void TearDownTestCase() {
|
||||
file_mgr_db.reset();
|
||||
config.reset();
|
||||
event_system::instance().stop();
|
||||
}
|
||||
};
|
||||
|
||||
using file_mgr_db_types = ::testing::Types<sqlite_file_mgr_db>;
|
||||
|
||||
template <typename db_t>
|
||||
std::unique_ptr<app_config> file_mgr_db_test<db_t>::config;
|
||||
|
||||
template <typename db_t> console_consumer file_mgr_db_test<db_t>::console_;
|
||||
|
||||
template <typename db_t>
|
||||
std::unique_ptr<db_t> file_mgr_db_test<db_t>::file_mgr_db;
|
||||
} // namespace repertory
|
||||
|
||||
#endif // REPERTORY_TEST_INCLUDE_FIXTURES_FILE_MGR_DB_FIXTURE_HPP
|
@ -496,20 +496,17 @@ TEST_F(file_manager_test,
|
||||
|
||||
auto stored_downloads = mgr.get_stored_downloads();
|
||||
EXPECT_EQ(std::size_t(1u), stored_downloads.size());
|
||||
std::cout << stored_downloads[0u].dump(2) << std::endl;
|
||||
|
||||
EXPECT_STREQ("/test_write_partial_download.txt",
|
||||
stored_downloads[0u]["path"].get<std::string>().c_str());
|
||||
stored_downloads[0U].api_path.c_str());
|
||||
EXPECT_EQ(utils::encryption::encrypting_reader::get_data_chunk_size(),
|
||||
stored_downloads[0u]["chunk_size"].get<std::size_t>());
|
||||
auto read_state = utils::string::to_dynamic_bitset(
|
||||
stored_downloads[0u]["read_state"].get<std::string>());
|
||||
EXPECT_TRUE(read_state[0u]);
|
||||
for (std::size_t i = 1u; i < read_state.size(); i++) {
|
||||
stored_downloads[0U].chunk_size);
|
||||
auto read_state = stored_downloads[0U].read_state;
|
||||
EXPECT_TRUE(read_state[0U]);
|
||||
for (std::size_t i = 1U; i < read_state.size(); i++) {
|
||||
EXPECT_FALSE(read_state[i]);
|
||||
}
|
||||
EXPECT_STREQ(source_path.c_str(),
|
||||
stored_downloads[0u]["source"].get<std::string>().c_str());
|
||||
EXPECT_STREQ(source_path.c_str(), stored_downloads[0u].source_path.c_str());
|
||||
|
||||
mgr.start();
|
||||
|
||||
|
96
repertory/repertory_test/src/file_mgr_db_test.cpp
Normal file
96
repertory/repertory_test/src/file_mgr_db_test.cpp
Normal file
@ -0,0 +1,96 @@
|
||||
/*
|
||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
||||
|
||||
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 "fixtures/file_mgr_db_fixture.hpp"
|
||||
|
||||
namespace repertory {
|
||||
TYPED_TEST_CASE(file_mgr_db_test, file_mgr_db_types);
|
||||
|
||||
TYPED_TEST(file_mgr_db_test, can_add_and_remove_resume) {
|
||||
this->file_mgr_db->clear();
|
||||
|
||||
EXPECT_TRUE(this->file_mgr_db->add_resume({
|
||||
"/test0",
|
||||
2ULL,
|
||||
{},
|
||||
"/src/test0",
|
||||
}));
|
||||
auto list = this->file_mgr_db->get_resume_list();
|
||||
EXPECT_EQ(1U, list.size());
|
||||
EXPECT_EQ(1U, list.size());
|
||||
EXPECT_STREQ("/test0", list.at(0U).api_path.c_str());
|
||||
EXPECT_EQ(2ULL, list.at(0U).chunk_size);
|
||||
EXPECT_STREQ("/src/test0", list.at(0U).source_path.c_str());
|
||||
|
||||
EXPECT_TRUE(this->file_mgr_db->remove_resume("/test0"));
|
||||
list = this->file_mgr_db->get_resume_list();
|
||||
EXPECT_TRUE(list.empty());
|
||||
}
|
||||
|
||||
TYPED_TEST(file_mgr_db_test, can_get_resume_list) {
|
||||
this->file_mgr_db->clear();
|
||||
|
||||
for (auto idx = 0U; idx < 5U; ++idx) {
|
||||
EXPECT_TRUE(this->file_mgr_db->add_resume({
|
||||
"/test1_" + std::to_string(idx),
|
||||
2ULL + idx,
|
||||
{},
|
||||
"/src/test1_" + std::to_string(idx),
|
||||
}));
|
||||
}
|
||||
|
||||
auto list = this->file_mgr_db->get_resume_list();
|
||||
EXPECT_EQ(5U, list.size());
|
||||
for (auto idx = 0U; idx < list.size(); ++idx) {
|
||||
EXPECT_STREQ(("/test1_" + std::to_string(idx)).c_str(),
|
||||
list.at(idx).api_path.c_str());
|
||||
EXPECT_EQ(2ULL + idx, list.at(idx).chunk_size);
|
||||
EXPECT_STREQ(("/src/test1_" + std::to_string(idx)).c_str(),
|
||||
list.at(idx).source_path.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST(file_mgr_db_test, can_replace_resume) {
|
||||
this->file_mgr_db->clear();
|
||||
|
||||
EXPECT_TRUE(this->file_mgr_db->add_resume({
|
||||
"/test0",
|
||||
2ULL,
|
||||
{},
|
||||
"/src/test0",
|
||||
}));
|
||||
EXPECT_TRUE(this->file_mgr_db->add_resume({
|
||||
"/test0",
|
||||
3ULL,
|
||||
{},
|
||||
"/src/test1",
|
||||
}));
|
||||
|
||||
auto list = this->file_mgr_db->get_resume_list();
|
||||
EXPECT_EQ(1U, list.size());
|
||||
EXPECT_STREQ("/test0", list.at(0U).api_path.c_str());
|
||||
EXPECT_EQ(3ULL, list.at(0U).chunk_size);
|
||||
EXPECT_STREQ("/src/test1", list.at(0U).source_path.c_str());
|
||||
|
||||
EXPECT_TRUE(this->file_mgr_db->remove_resume("/test0"));
|
||||
}
|
||||
} // namespace repertory
|
Loading…
x
Reference in New Issue
Block a user