Compare commits
1 Commits
d54d724953
...
v2.0.4-rc
Author | SHA1 | Date | |
---|---|---|---|
24418ba03d |
12
CHANGELOG.md
12
CHANGELOG.md
@ -2,21 +2,27 @@
|
||||
|
||||
## v2.0.4-rc
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
* `renterd` v2.0.0+ is now required. Prior versions will fail to mount.
|
||||
|
||||
### Issues
|
||||
|
||||
* ~~\#12 [Unit Test] Complete all providers unit tests~~
|
||||
* ~~\#21 [Unit Test] Complete WinFSP unit tests~~
|
||||
* ~~\#22 [Unit Test] Complete FUSE unit tests~~
|
||||
* \#35 [bug] Low frequency check is set to '0' instead of 1 hour by default
|
||||
* \#36 [bug] Max cache size bytes is set to '0' by default
|
||||
|
||||
### Changes from v2.0.3-rc
|
||||
|
||||
* Added Sia API version check prior to mounting
|
||||
* Added back `-cv` (check version) CLI option
|
||||
* Continue documentation updates
|
||||
* Fixed setting `ApiAuth` via `set_value_by_name`
|
||||
* Fixed setting `HostConfig.ApiUser` via `set_value_by_name`
|
||||
* Fixed setting `HostConfig.Path` via `set_value_by_name`
|
||||
* Fixed setting `HostConfig.Protocol` via `set_value_by_name`
|
||||
* Improved ring buffer read-ahead
|
||||
* Integrated `renterd` version 2.0.0
|
||||
* Prefer using local cache file when opening files
|
||||
* Refactored `app_config` unit tests
|
||||
* Refactored polling to be more accurate on scheduling tasks
|
||||
|
||||
|
@ -58,6 +58,10 @@ if(PROJECT_IS_MINGW)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (PROJECT_ENABLE_V2_ERRORS)
|
||||
add_definitions(-DPROJECT_ENABLE_V2_ERRORS)
|
||||
endif()
|
||||
|
||||
include(cmake/settings.cmake)
|
||||
|
||||
include(cmake/flags.cmake)
|
||||
@ -143,6 +147,7 @@ endif()
|
||||
-DPROJECT_COPYRIGHT=${PROJECT_COPYRIGHT}
|
||||
-DPROJECT_DESC=${PROJECT_DESC}
|
||||
-DPROJECT_DIST_DIR=${PROJECT_DIST_DIR}
|
||||
-DPROJECT_ENABLE_V2_ERRORS=${PROJECT_ENABLE_V2_ERRORS}
|
||||
-DPROJECT_ENABLE_WIN32_LONG_PATH_NAMES=${PROJECT_ENABLE_WIN32_LONG_PATH_NAMES}
|
||||
-DPROJECT_ENABLE_BOOST=${PROJECT_ENABLE_BOOST}
|
||||
-DPROJECT_ENABLE_CPP_HTTPLIB=${PROJECT_ENABLE_CPP_HTTPLIB}
|
||||
|
@ -14,7 +14,7 @@ on Windows.
|
||||
|
||||
## Minimum Requirements
|
||||
|
||||
* [Sia renterd](https://github.com/SiaFoundation/renterd/releases) v0.4.0+ for Sia support
|
||||
* [Sia renterd](https://github.com/SiaFoundation/renterd/releases) v2.0.0+ for Sia support
|
||||
* Only 64-bit operating systems are supported
|
||||
* By default, Linux requires `fusermount3`; otherwise, `repertory` must be manually compiled with `libfuse2` support
|
||||
* Windows requires the following dependencies to be installed:
|
||||
|
@ -0,0 +1,78 @@
|
||||
/*
|
||||
Copyright <2018-2025> <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_EVENTS_TYPES_PRODIVER_INVALID_VERSION_HPP_
|
||||
#define REPERTORY_INCLUDE_EVENTS_TYPES_PRODIVER_INVALID_VERSION_HPP_
|
||||
|
||||
#include "events/i_event.hpp"
|
||||
#include "types/repertory.hpp"
|
||||
|
||||
namespace repertory {
|
||||
struct provider_invalid_version final : public i_event {
|
||||
provider_invalid_version() = default;
|
||||
provider_invalid_version(std::string_view function_name_,
|
||||
std::string required_version_,
|
||||
std::string returned_version_)
|
||||
: function_name(std::string(function_name_)),
|
||||
required_version(std::move(required_version_)),
|
||||
returned_version(std::move(returned_version_)) {}
|
||||
|
||||
static constexpr const event_level level{event_level::error};
|
||||
static constexpr const std::string_view name{"provider_invalid_version"};
|
||||
|
||||
std::string function_name;
|
||||
std::string required_version;
|
||||
std::string returned_version;
|
||||
|
||||
[[nodiscard]] auto get_event_level() const -> event_level override {
|
||||
return level;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_name() const -> std::string_view override {
|
||||
return name;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_single_line() const -> std::string override {
|
||||
return fmt::format("{}|func|{}|required|{}|returned|{}", name,
|
||||
function_name, required_version, returned_version);
|
||||
}
|
||||
};
|
||||
} // namespace repertory
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
template <> struct adl_serializer<repertory::provider_invalid_version> {
|
||||
static void to_json(json &data,
|
||||
const repertory::provider_invalid_version &value) {
|
||||
data["function_name"] = value.function_name;
|
||||
data["required_version"] = value.required_version;
|
||||
data["returned_version"] = value.returned_version;
|
||||
}
|
||||
|
||||
static void from_json(const json &data,
|
||||
repertory::provider_invalid_version &value) {
|
||||
data.at("function_name").get_to(value.function_name);
|
||||
data.at("required_version").get_to(value.required_version);
|
||||
data.at("returned_version").get_to(value.returned_version);
|
||||
}
|
||||
};
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
|
||||
#endif // REPERTORY_INCLUDE_EVENTS_TYPES_PRODIVER_INVALID_VERSION_HPP_
|
@ -85,6 +85,13 @@ private:
|
||||
void remove_deleted_files(stop_type &stop_requested);
|
||||
|
||||
public:
|
||||
[[nodiscard]] auto check_version(std::string &required_version,
|
||||
std::string &returned_version) const
|
||||
-> bool override {
|
||||
required_version = returned_version = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto create_directory(const std::string &api_path,
|
||||
api_meta_map &meta) -> api_error override;
|
||||
|
||||
|
@ -31,6 +31,10 @@ class i_provider {
|
||||
INTERFACE_SETUP(i_provider);
|
||||
|
||||
public:
|
||||
[[nodiscard]] virtual auto check_version(std::string &required_version,
|
||||
std::string &returned_version) const
|
||||
-> bool = 0;
|
||||
|
||||
[[nodiscard]] virtual auto create_directory(const std::string &api_path,
|
||||
api_meta_map &meta)
|
||||
-> api_error = 0;
|
||||
|
@ -113,6 +113,13 @@ protected:
|
||||
-> api_error override;
|
||||
|
||||
public:
|
||||
[[nodiscard]] auto check_version(std::string &required_version,
|
||||
std::string &returned_version) const
|
||||
-> bool override {
|
||||
required_version = returned_version = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
[[nodiscard]] static auto convert_api_date(std::string_view date)
|
||||
-> std::uint64_t;
|
||||
|
||||
|
@ -80,6 +80,10 @@ protected:
|
||||
-> api_error override;
|
||||
|
||||
public:
|
||||
[[nodiscard]] auto check_version(std::string &required_version,
|
||||
std::string &returned_version) const
|
||||
-> bool override;
|
||||
|
||||
[[nodiscard]] auto get_directory_item_count(const std::string &api_path) const
|
||||
-> std::uint64_t override;
|
||||
|
||||
|
@ -43,8 +43,8 @@
|
||||
#include "utils/utils.hpp"
|
||||
|
||||
namespace repertory::remote_fuse {
|
||||
auto remote_fuse_drive::access_impl(std::string api_path,
|
||||
int mask) -> api_error {
|
||||
auto remote_fuse_drive::access_impl(std::string api_path, int mask)
|
||||
-> api_error {
|
||||
return utils::to_api_error(
|
||||
remote_instance_->fuse_access(api_path.c_str(), mask));
|
||||
}
|
||||
@ -62,8 +62,8 @@ auto remote_fuse_drive::chmod_impl(std::string api_path, mode_t mode,
|
||||
struct fuse_file_info * /*f_info*/)
|
||||
-> api_error {
|
||||
#else
|
||||
auto remote_fuse_drive::chmod_impl(std::string api_path,
|
||||
mode_t mode) -> api_error {
|
||||
auto remote_fuse_drive::chmod_impl(std::string api_path, mode_t mode)
|
||||
-> api_error {
|
||||
#endif
|
||||
return utils::to_api_error(remote_instance_->fuse_chmod(
|
||||
api_path.c_str(), static_cast<remote::file_mode>(mode)));
|
||||
@ -74,8 +74,8 @@ auto remote_fuse_drive::chown_impl(std::string api_path, uid_t uid, gid_t gid,
|
||||
struct fuse_file_info * /*f_info*/)
|
||||
-> api_error {
|
||||
#else
|
||||
auto remote_fuse_drive::chown_impl(std::string api_path, uid_t uid,
|
||||
gid_t gid) -> api_error {
|
||||
auto remote_fuse_drive::chown_impl(std::string api_path, uid_t uid, gid_t gid)
|
||||
-> api_error {
|
||||
#endif
|
||||
return utils::to_api_error(
|
||||
remote_instance_->fuse_chown(api_path.c_str(), uid, gid));
|
||||
@ -94,7 +94,7 @@ void remote_fuse_drive::destroy_impl(void *ptr) {
|
||||
REPERTORY_USES_FUNCTION_NAME();
|
||||
|
||||
event_system::instance().raise<drive_unmount_pending>(function_name,
|
||||
get_mount_location());
|
||||
get_mount_location());
|
||||
|
||||
if (server_) {
|
||||
server_->stop();
|
||||
@ -116,14 +116,15 @@ void remote_fuse_drive::destroy_impl(void *ptr) {
|
||||
}
|
||||
|
||||
event_system::instance().raise<drive_unmounted>(function_name,
|
||||
get_mount_location());
|
||||
get_mount_location());
|
||||
|
||||
fuse_base::destroy_impl(ptr);
|
||||
}
|
||||
|
||||
auto remote_fuse_drive::fgetattr_impl(
|
||||
std::string api_path, struct stat *unix_st,
|
||||
struct fuse_file_info *f_info) -> api_error {
|
||||
auto remote_fuse_drive::fgetattr_impl(std::string api_path,
|
||||
struct stat *unix_st,
|
||||
struct fuse_file_info *f_info)
|
||||
-> api_error {
|
||||
remote::stat r_stat{};
|
||||
auto directory = false;
|
||||
|
||||
@ -184,8 +185,8 @@ auto remote_fuse_drive::getattr_impl(std::string api_path, struct stat *unix_st,
|
||||
struct fuse_file_info * /*f_info*/)
|
||||
-> api_error {
|
||||
#else
|
||||
auto remote_fuse_drive::getattr_impl(std::string api_path,
|
||||
struct stat *unix_st) -> api_error {
|
||||
auto remote_fuse_drive::getattr_impl(std::string api_path, struct stat *unix_st)
|
||||
-> api_error {
|
||||
#endif
|
||||
bool directory = false;
|
||||
remote::stat r_stat{};
|
||||
@ -263,14 +264,14 @@ auto remote_fuse_drive::init_impl(struct fuse_conn_info *conn) -> void * {
|
||||
server_ = std::make_shared<server>(config_);
|
||||
server_->start();
|
||||
event_system::instance().raise<drive_mounted>(function_name,
|
||||
get_mount_location());
|
||||
get_mount_location());
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
auto remote_fuse_drive::mkdir_impl(std::string api_path,
|
||||
mode_t mode) -> api_error {
|
||||
auto remote_fuse_drive::mkdir_impl(std::string api_path, mode_t mode)
|
||||
-> api_error {
|
||||
return utils::to_api_error(remote_instance_->fuse_mkdir(
|
||||
api_path.c_str(), static_cast<remote::file_mode>(mode)));
|
||||
}
|
||||
@ -295,8 +296,9 @@ auto remote_fuse_drive::open_impl(std::string api_path,
|
||||
f_info->fh));
|
||||
}
|
||||
|
||||
auto remote_fuse_drive::opendir_impl(
|
||||
std::string api_path, struct fuse_file_info *f_info) -> api_error {
|
||||
auto remote_fuse_drive::opendir_impl(std::string api_path,
|
||||
struct fuse_file_info *f_info)
|
||||
-> api_error {
|
||||
if ((f_info->flags & O_APPEND) == O_APPEND ||
|
||||
(f_info->flags & O_EXCL) == O_EXCL) {
|
||||
return api_error::directory_exists;
|
||||
@ -309,12 +311,14 @@ auto remote_fuse_drive::opendir_impl(
|
||||
void remote_fuse_drive::populate_stat(const remote::stat &r_stat,
|
||||
bool directory, struct stat &unix_st) {
|
||||
std::memset(&unix_st, 0, sizeof(struct stat));
|
||||
unix_st.st_blksize = r_stat.st_blksize;
|
||||
unix_st.st_blocks = static_cast<blkcnt_t>(r_stat.st_blocks);
|
||||
unix_st.st_blksize =
|
||||
static_cast<decltype(unix_st.st_blksize)>(r_stat.st_blksize);
|
||||
unix_st.st_blocks =
|
||||
static_cast<decltype(unix_st.st_blocks)>(r_stat.st_blocks);
|
||||
unix_st.st_gid = r_stat.st_gid;
|
||||
unix_st.st_mode = (directory ? S_IFDIR : S_IFREG) | r_stat.st_mode;
|
||||
unix_st.st_nlink = r_stat.st_nlink;
|
||||
unix_st.st_size = static_cast<off_t>(r_stat.st_size);
|
||||
unix_st.st_size = static_cast<decltype(unix_st.st_size)>(r_stat.st_size);
|
||||
unix_st.st_uid = r_stat.st_uid;
|
||||
|
||||
#if defined(__APPLE__)
|
||||
@ -373,14 +377,18 @@ auto remote_fuse_drive::read_impl(std::string api_path, char *buffer,
|
||||
}
|
||||
|
||||
#if FUSE_USE_VERSION >= 30
|
||||
auto remote_fuse_drive::readdir_impl(
|
||||
std::string api_path, void *buf, fuse_fill_dir_t fuse_fill_dir,
|
||||
off_t offset, struct fuse_file_info *f_info,
|
||||
fuse_readdir_flags /*flags*/) -> api_error {
|
||||
auto remote_fuse_drive::readdir_impl(std::string api_path, void *buf,
|
||||
fuse_fill_dir_t fuse_fill_dir,
|
||||
off_t offset,
|
||||
struct fuse_file_info *f_info,
|
||||
fuse_readdir_flags /*flags*/)
|
||||
-> api_error {
|
||||
#else
|
||||
auto remote_fuse_drive::readdir_impl(
|
||||
std::string api_path, void *buf, fuse_fill_dir_t fuse_fill_dir,
|
||||
off_t offset, struct fuse_file_info *f_info) -> api_error {
|
||||
auto remote_fuse_drive::readdir_impl(std::string api_path, void *buf,
|
||||
fuse_fill_dir_t fuse_fill_dir,
|
||||
off_t offset,
|
||||
struct fuse_file_info *f_info)
|
||||
-> api_error {
|
||||
#endif
|
||||
std::string item_path;
|
||||
int res = 0;
|
||||
@ -408,14 +416,16 @@ auto remote_fuse_drive::readdir_impl(
|
||||
return utils::to_api_error(res);
|
||||
}
|
||||
|
||||
auto remote_fuse_drive::release_impl(
|
||||
std::string api_path, struct fuse_file_info *f_info) -> api_error {
|
||||
auto remote_fuse_drive::release_impl(std::string api_path,
|
||||
struct fuse_file_info *f_info)
|
||||
-> api_error {
|
||||
return utils::to_api_error(
|
||||
remote_instance_->fuse_release(api_path.c_str(), f_info->fh));
|
||||
}
|
||||
|
||||
auto remote_fuse_drive::releasedir_impl(
|
||||
std::string api_path, struct fuse_file_info *f_info) -> api_error {
|
||||
auto remote_fuse_drive::releasedir_impl(std::string api_path,
|
||||
struct fuse_file_info *f_info)
|
||||
-> api_error {
|
||||
return utils::to_api_error(
|
||||
remote_instance_->fuse_releasedir(api_path.c_str(), f_info->fh));
|
||||
}
|
||||
@ -512,8 +522,8 @@ api_error remote_fuse_drive::statfs_x_impl(std::string api_path,
|
||||
return utils::to_api_error(res);
|
||||
}
|
||||
#else // __APPLE__
|
||||
auto remote_fuse_drive::statfs_impl(std::string api_path,
|
||||
struct statvfs *stbuf) -> api_error {
|
||||
auto remote_fuse_drive::statfs_impl(std::string api_path, struct statvfs *stbuf)
|
||||
-> api_error {
|
||||
auto res = statvfs(config_.get_data_directory().c_str(), stbuf);
|
||||
if (res == 0) {
|
||||
remote::statfs r_stat{};
|
||||
@ -540,8 +550,8 @@ auto remote_fuse_drive::truncate_impl(std::string api_path, off_t size,
|
||||
struct fuse_file_info * /*f_info*/)
|
||||
-> api_error {
|
||||
#else
|
||||
auto remote_fuse_drive::truncate_impl(std::string api_path,
|
||||
off_t size) -> api_error {
|
||||
auto remote_fuse_drive::truncate_impl(std::string api_path, off_t size)
|
||||
-> api_error {
|
||||
#endif
|
||||
return utils::to_api_error(remote_instance_->fuse_truncate(
|
||||
api_path.c_str(), static_cast<remote::file_offset>(size)));
|
||||
@ -552,9 +562,10 @@ auto remote_fuse_drive::unlink_impl(std::string api_path) -> api_error {
|
||||
}
|
||||
|
||||
#if FUSE_USE_VERSION >= 30
|
||||
auto remote_fuse_drive::utimens_impl(
|
||||
std::string api_path, const struct timespec tv[2],
|
||||
struct fuse_file_info * /*f_info*/) -> api_error {
|
||||
auto remote_fuse_drive::utimens_impl(std::string api_path,
|
||||
const struct timespec tv[2],
|
||||
struct fuse_file_info * /*f_info*/)
|
||||
-> api_error {
|
||||
#else
|
||||
auto remote_fuse_drive::utimens_impl(std::string api_path,
|
||||
const struct timespec tv[2]) -> api_error {
|
||||
|
@ -466,6 +466,13 @@ auto file_manager::open(const std::string &api_path, bool directory,
|
||||
return download_type::default_;
|
||||
}
|
||||
|
||||
if (utils::file::file{fsi.source_path}.exists()) {
|
||||
auto size = utils::file::file{fsi.source_path}.size();
|
||||
if (size.has_value() && *size == fsi.size) {
|
||||
return download_type::default_;
|
||||
}
|
||||
}
|
||||
|
||||
if (type == download_type::direct) {
|
||||
return type;
|
||||
}
|
||||
|
@ -98,19 +98,23 @@ auto ring_buffer_base::close() -> bool {
|
||||
return res;
|
||||
}
|
||||
|
||||
auto ring_buffer_base::download_chunk(std::size_t chunk,
|
||||
bool skip_active) -> api_error {
|
||||
auto ring_buffer_base::download_chunk(std::size_t chunk, bool skip_active)
|
||||
-> api_error {
|
||||
REPERTORY_USES_FUNCTION_NAME();
|
||||
|
||||
unique_mutex_lock chunk_lock(chunk_mtx_);
|
||||
const auto unlock_and_notify = [this, &chunk_lock]() {
|
||||
if (not skip_active) {
|
||||
ring_pos_ = chunk;
|
||||
}
|
||||
|
||||
const auto notify_and_unlock = [this, &chunk_lock]() {
|
||||
chunk_notify_.notify_all();
|
||||
chunk_lock.unlock();
|
||||
};
|
||||
|
||||
const auto unlock_and_return =
|
||||
[&unlock_and_notify](api_error res) -> api_error {
|
||||
unlock_and_notify();
|
||||
[¬ify_and_unlock](api_error res) -> api_error {
|
||||
notify_and_unlock();
|
||||
return res;
|
||||
};
|
||||
|
||||
@ -124,7 +128,7 @@ auto ring_buffer_base::download_chunk(std::size_t chunk,
|
||||
}
|
||||
|
||||
auto active_download = get_active_downloads().at(chunk);
|
||||
unlock_and_notify();
|
||||
notify_and_unlock();
|
||||
|
||||
return active_download->wait();
|
||||
}
|
||||
@ -142,7 +146,7 @@ auto ring_buffer_base::download_chunk(std::size_t chunk,
|
||||
chunk == (total_chunks_ - 1U) ? get_last_chunk_size()
|
||||
: get_chunk_size(),
|
||||
};
|
||||
unlock_and_notify();
|
||||
notify_and_unlock();
|
||||
|
||||
auto result{
|
||||
get_provider().read_file_bytes(get_api_path(), data_size, data_offset,
|
||||
@ -167,7 +171,7 @@ auto ring_buffer_base::download_chunk(std::size_t chunk,
|
||||
}
|
||||
|
||||
get_active_downloads().erase(chunk);
|
||||
unlock_and_notify();
|
||||
notify_and_unlock();
|
||||
|
||||
active_download->notify(result);
|
||||
return result;
|
||||
@ -226,7 +230,6 @@ auto ring_buffer_base::read(std::size_t read_size, std::uint64_t read_offset,
|
||||
} else if (chunk < ring_pos_) {
|
||||
reverse(ring_pos_ - chunk);
|
||||
}
|
||||
|
||||
res = download_chunk(chunk, false);
|
||||
if (res != api_error::success) {
|
||||
if (res == api_error::invalid_ring_buffer_position) {
|
||||
@ -264,38 +267,46 @@ void ring_buffer_base::reader_thread() {
|
||||
REPERTORY_USES_FUNCTION_NAME();
|
||||
|
||||
unique_mutex_lock chunk_lock(chunk_mtx_);
|
||||
auto next_chunk{ring_pos_};
|
||||
chunk_notify_.notify_all();
|
||||
chunk_lock.unlock();
|
||||
const auto notify_and_unlock = [this, &chunk_lock]() {
|
||||
chunk_notify_.notify_all();
|
||||
chunk_lock.unlock();
|
||||
};
|
||||
|
||||
auto last_pos = ring_pos_;
|
||||
auto next_chunk = ring_pos_;
|
||||
notify_and_unlock();
|
||||
|
||||
while (not get_stop_requested()) {
|
||||
chunk_lock.lock();
|
||||
|
||||
next_chunk = next_chunk + 1U > ring_end_ ? ring_begin_ : next_chunk + 1U;
|
||||
const auto check_and_wait = [this, &chunk_lock, &next_chunk]() {
|
||||
if (last_pos == ring_pos_) {
|
||||
++next_chunk;
|
||||
} else {
|
||||
next_chunk = ring_pos_ + 1U;
|
||||
last_pos = ring_pos_;
|
||||
}
|
||||
|
||||
if (next_chunk > ring_end_) {
|
||||
next_chunk = ring_begin_;
|
||||
}
|
||||
|
||||
if (read_state_[next_chunk % read_state_.size()]) {
|
||||
if (get_stop_requested()) {
|
||||
chunk_notify_.notify_all();
|
||||
chunk_lock.unlock();
|
||||
notify_and_unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
if (get_read_state().all()) {
|
||||
chunk_notify_.wait(chunk_lock);
|
||||
last_pos = ring_pos_;
|
||||
next_chunk = ring_pos_;
|
||||
}
|
||||
|
||||
chunk_notify_.notify_all();
|
||||
chunk_lock.unlock();
|
||||
};
|
||||
|
||||
if (read_state_[next_chunk % read_state_.size()]) {
|
||||
check_and_wait();
|
||||
notify_and_unlock();
|
||||
continue;
|
||||
}
|
||||
|
||||
chunk_notify_.notify_all();
|
||||
chunk_lock.unlock();
|
||||
|
||||
notify_and_unlock();
|
||||
download_chunk(next_chunk, true);
|
||||
}
|
||||
|
||||
@ -351,30 +362,31 @@ void ring_buffer_base::update_position(std::size_t count, bool is_forward) {
|
||||
if (is_forward ? (ring_pos_ + count) <= ring_end_
|
||||
: (ring_pos_ - count) >= ring_begin_) {
|
||||
ring_pos_ += is_forward ? count : -count;
|
||||
} else {
|
||||
auto delta = is_forward ? count - (ring_end_ - ring_pos_)
|
||||
: count - (ring_pos_ - ring_begin_);
|
||||
|
||||
if (delta >= read_state_.size()) {
|
||||
read_state_.set(0U, read_state_.size(), false);
|
||||
ring_pos_ += is_forward ? count : -count;
|
||||
ring_begin_ += is_forward ? delta : -delta;
|
||||
} else {
|
||||
for (std::size_t idx = 0U; idx < delta; ++idx) {
|
||||
if (is_forward) {
|
||||
read_state_[(ring_begin_ + idx) % read_state_.size()] = false;
|
||||
} else {
|
||||
read_state_[(ring_end_ - idx) % read_state_.size()] = false;
|
||||
}
|
||||
}
|
||||
ring_begin_ += is_forward ? delta : -delta;
|
||||
ring_pos_ += is_forward ? count : -count;
|
||||
}
|
||||
|
||||
ring_end_ =
|
||||
std::min(total_chunks_ - 1U, ring_begin_ + read_state_.size() - 1U);
|
||||
chunk_notify_.notify_all();
|
||||
return;
|
||||
}
|
||||
|
||||
auto delta = is_forward ? count - (ring_end_ - ring_pos_)
|
||||
: count - (ring_pos_ - ring_begin_);
|
||||
if (delta >= read_state_.size()) {
|
||||
read_state_.set(0U, read_state_.size(), false);
|
||||
ring_pos_ += is_forward ? count : -count;
|
||||
ring_begin_ += is_forward ? delta : -delta;
|
||||
} else {
|
||||
for (std::size_t idx = 0U; idx < delta; ++idx) {
|
||||
if (is_forward) {
|
||||
read_state_[(ring_begin_ + idx) % read_state_.size()] = false;
|
||||
} else {
|
||||
read_state_[(ring_end_ - idx) % read_state_.size()] = false;
|
||||
}
|
||||
}
|
||||
ring_begin_ += is_forward ? delta : -delta;
|
||||
ring_pos_ += is_forward ? count : -count;
|
||||
}
|
||||
|
||||
ring_end_ =
|
||||
std::min(total_chunks_ - 1U, ring_begin_ + read_state_.size() - 1U);
|
||||
|
||||
chunk_notify_.notify_all();
|
||||
}
|
||||
} // namespace repertory
|
||||
|
@ -50,10 +50,6 @@
|
||||
|
||||
namespace repertory {
|
||||
auto project_initialize() -> bool {
|
||||
spdlog::drop_all();
|
||||
spdlog::flush_every(std::chrono::seconds(10));
|
||||
spdlog::set_pattern("%Y-%m-%d|%T.%e|%^%l%$|%v");
|
||||
|
||||
#if defined(PROJECT_REQUIRE_ALPINE) && !defined(PROJECT_IS_MINGW)
|
||||
{
|
||||
static constexpr const auto guard_size{4096U};
|
||||
@ -68,6 +64,10 @@ auto project_initialize() -> bool {
|
||||
}
|
||||
#endif // defined(PROJECT_REQUIRE_ALPINE) && !defined (PROJECT_IS_MINGW)
|
||||
|
||||
spdlog::drop_all();
|
||||
spdlog::flush_every(std::chrono::seconds(10));
|
||||
spdlog::set_pattern("%Y-%m-%d|%T.%e|%^%l%$|%v");
|
||||
|
||||
#if defined(PROJECT_ENABLE_LIBSODIUM)
|
||||
{
|
||||
if (sodium_init() == -1) {
|
||||
@ -77,7 +77,9 @@ auto project_initialize() -> bool {
|
||||
#endif // defined(PROJECT_ENABLE_LIBSODIUM)
|
||||
|
||||
#if defined(PROJECT_ENABLE_OPENSSL)
|
||||
{ SSL_library_init(); }
|
||||
{
|
||||
SSL_library_init();
|
||||
}
|
||||
#endif // defined(PROJECT_ENABLE_OPENSSL)
|
||||
|
||||
#if defined(PROJECT_ENABLE_CURL)
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "events/types/orphaned_file_processing_failed.hpp"
|
||||
#include "events/types/orphaned_source_file_detected.hpp"
|
||||
#include "events/types/orphaned_source_file_removed.hpp"
|
||||
#include "events/types/provider_invalid_version.hpp"
|
||||
#include "events/types/provider_offline.hpp"
|
||||
#include "events/types/provider_upload_begin.hpp"
|
||||
#include "events/types/provider_upload_end.hpp"
|
||||
@ -840,6 +841,14 @@ auto base_provider::start(api_item_added_callback api_item_added,
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string returned_version;
|
||||
std::string required_version;
|
||||
if (not check_version(required_version, returned_version)) {
|
||||
event_system::instance().raise<provider_invalid_version>(
|
||||
function_name, required_version, returned_version);
|
||||
return false;
|
||||
}
|
||||
|
||||
cache_size_mgr::instance().initialize(&config_);
|
||||
|
||||
polling::instance().set_callback({
|
||||
|
@ -495,7 +495,19 @@ auto s3_provider::get_file(const std::string &api_path, api_file &file) const
|
||||
get_object_info(false, api_path, is_encrypted, object_name, result),
|
||||
};
|
||||
if (res != api_error::success) {
|
||||
return res;
|
||||
if (res != api_error::item_not_found) {
|
||||
return res;
|
||||
}
|
||||
|
||||
bool exists{};
|
||||
res = is_directory(api_path, exists);
|
||||
if (res != api_error::success) {
|
||||
utils::error::raise_api_path_error(
|
||||
function_name, api_path, res,
|
||||
"failed to determine if directory exists");
|
||||
}
|
||||
|
||||
return exists ? api_error::directory_exists : api_error::item_not_found;
|
||||
}
|
||||
|
||||
file.api_path = api_path;
|
||||
|
@ -32,8 +32,8 @@
|
||||
#include "providers/base_provider.hpp"
|
||||
#include "providers/s3/s3_provider.hpp"
|
||||
#include "types/repertory.hpp"
|
||||
#include "utils/common.hpp"
|
||||
#include "utils/error_utils.hpp"
|
||||
#include "utils/file_utils.hpp"
|
||||
#include "utils/path.hpp"
|
||||
#include "utils/polling.hpp"
|
||||
#include "utils/string.hpp"
|
||||
@ -63,6 +63,54 @@ namespace repertory {
|
||||
sia_provider::sia_provider(app_config &config, i_http_comm &comm)
|
||||
: base_provider(config, comm) {}
|
||||
|
||||
auto sia_provider::check_version(std::string &required_version,
|
||||
std::string &returned_version) const -> bool {
|
||||
REPERTORY_USES_FUNCTION_NAME();
|
||||
|
||||
required_version = "2.0.0";
|
||||
|
||||
try {
|
||||
curl::requests::http_get get{};
|
||||
get.allow_timeout = true;
|
||||
get.path = "/api/bus/state";
|
||||
|
||||
nlohmann::json state_data;
|
||||
std::string error_data;
|
||||
get.response_handler = [&error_data, &state_data](auto &&data,
|
||||
long response_code) {
|
||||
if (response_code == http_error_codes::ok) {
|
||||
state_data = nlohmann::json::parse(data.begin(), data.end());
|
||||
return;
|
||||
}
|
||||
|
||||
error_data = std::string(data.begin(), data.end());
|
||||
};
|
||||
|
||||
long response_code{};
|
||||
stop_type stop_requested{};
|
||||
if (not get_comm().make_request(get, response_code, stop_requested)) {
|
||||
utils::error::raise_error(function_name, response_code,
|
||||
"failed to check state");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (response_code != http_error_codes::ok) {
|
||||
utils::error::raise_error(
|
||||
function_name, response_code,
|
||||
fmt::format("failed to check state|response|{}", error_data));
|
||||
return false;
|
||||
}
|
||||
|
||||
returned_version = state_data.at("version").get<std::string>().substr(1U);
|
||||
return utils::compare_version_strings(returned_version, required_version) >=
|
||||
0;
|
||||
} catch (const std::exception &e) {
|
||||
utils::error::raise_error(function_name, e, "failed to check version");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
auto sia_provider::create_directory_impl(const std::string &api_path,
|
||||
api_meta_map & /* meta */)
|
||||
-> api_error {
|
||||
@ -70,7 +118,7 @@ auto sia_provider::create_directory_impl(const std::string &api_path,
|
||||
|
||||
curl::requests::http_put_file put_file{};
|
||||
put_file.allow_timeout = true;
|
||||
put_file.path = "/api/worker/objects" + api_path + "/";
|
||||
put_file.path = "/api/worker/object" + api_path + "/";
|
||||
put_file.query["bucket"] = get_bucket(get_sia_config());
|
||||
|
||||
std::string error_data;
|
||||
@ -112,10 +160,10 @@ auto sia_provider::get_directory_item_count(const std::string &api_path) const
|
||||
}
|
||||
|
||||
std::uint64_t item_count{};
|
||||
if (object_list.contains("entries")) {
|
||||
for (const auto &entry : object_list.at("entries")) {
|
||||
if (object_list.contains("objects")) {
|
||||
for (const auto &entry : object_list.at("objects")) {
|
||||
try {
|
||||
auto name{entry.at("name").get<std::string>()};
|
||||
auto name{entry.at("key").get<std::string>()};
|
||||
auto entry_api_path{utils::path::create_api_path(name)};
|
||||
if (utils::string::ends_with(name, "/") &&
|
||||
(entry_api_path == api_path)) {
|
||||
@ -149,10 +197,10 @@ auto sia_provider::get_directory_items_impl(const std::string &api_path,
|
||||
return api_error::comm_error;
|
||||
}
|
||||
|
||||
if (object_list.contains("entries")) {
|
||||
for (const auto &entry : object_list.at("entries")) {
|
||||
if (object_list.contains("objects")) {
|
||||
for (const auto &entry : object_list.at("objects")) {
|
||||
try {
|
||||
auto name{entry.at("name").get<std::string>()};
|
||||
auto name{entry.at("key").get<std::string>()};
|
||||
auto entry_api_path{utils::path::create_api_path(name)};
|
||||
|
||||
auto directory{utils::string::ends_with(name, "/")};
|
||||
@ -206,22 +254,28 @@ auto sia_provider::get_file(const std::string &api_path, api_file &file) const
|
||||
json file_data{};
|
||||
auto res{get_object_info(api_path, file_data)};
|
||||
if (res != api_error::success) {
|
||||
return res;
|
||||
if (res != api_error::item_not_found) {
|
||||
return res;
|
||||
}
|
||||
|
||||
bool exists{};
|
||||
res = is_directory(api_path, exists);
|
||||
if (res != api_error::success) {
|
||||
utils::error::raise_api_path_error(
|
||||
function_name, api_path, res,
|
||||
"failed to determine if directory exists");
|
||||
}
|
||||
|
||||
return exists ? api_error::directory_exists : api_error::item_not_found;
|
||||
}
|
||||
|
||||
auto slabs{file_data["object"]["Slabs"]};
|
||||
auto size{
|
||||
std::accumulate(
|
||||
slabs.begin(), slabs.end(), std::uint64_t(0U),
|
||||
[](auto &&total_size, const json &slab) -> std::uint64_t {
|
||||
return total_size + slab["Length"].get<std::uint64_t>();
|
||||
}),
|
||||
file_data.at("size").get<std::uint64_t>(),
|
||||
};
|
||||
|
||||
api_meta_map meta{};
|
||||
if (get_item_meta(api_path, meta) == api_error::item_not_found) {
|
||||
file = create_api_file(api_path, "", size,
|
||||
get_last_modified(file_data["object"]));
|
||||
file = create_api_file(api_path, "", size, get_last_modified(file_data));
|
||||
get_api_item_added()(false, file);
|
||||
} else {
|
||||
file = create_api_file(api_path, size, meta);
|
||||
@ -249,9 +303,9 @@ auto sia_provider::get_file_list(api_file_list &list,
|
||||
return api_error::comm_error;
|
||||
}
|
||||
|
||||
if (object_list.contains("entries")) {
|
||||
for (const auto &entry : object_list.at("entries")) {
|
||||
auto name{entry.at("name").get<std::string>()};
|
||||
if (object_list.contains("objects")) {
|
||||
for (const auto &entry : object_list.at("objects")) {
|
||||
auto name{entry.at("key").get<std::string>()};
|
||||
auto entry_api_path{utils::path::create_api_path(name)};
|
||||
|
||||
if (utils::string::ends_with(name, "/")) {
|
||||
@ -312,8 +366,9 @@ auto sia_provider::get_object_info(const std::string &api_path,
|
||||
try {
|
||||
curl::requests::http_get get{};
|
||||
get.allow_timeout = true;
|
||||
get.path = "/api/bus/objects" + api_path;
|
||||
get.path = "/api/bus/object" + api_path;
|
||||
get.query["bucket"] = get_bucket(get_sia_config());
|
||||
get.query["onlymetadata"] = "true";
|
||||
|
||||
std::string error_data;
|
||||
get.response_handler = [&error_data, &object_info](auto &&data,
|
||||
@ -361,6 +416,7 @@ auto sia_provider::get_object_list(const std::string &api_path,
|
||||
get.allow_timeout = true;
|
||||
get.path = "/api/bus/objects" + api_path + "/";
|
||||
get.query["bucket"] = get_bucket(get_sia_config());
|
||||
get.query["delimiter"] = "/";
|
||||
|
||||
std::string error_data;
|
||||
get.response_handler = [&error_data, &object_list](auto &&data,
|
||||
@ -404,7 +460,7 @@ auto sia_provider::get_total_drive_space() const -> std::uint64_t {
|
||||
try {
|
||||
curl::requests::http_get get{};
|
||||
get.allow_timeout = true;
|
||||
get.path = "/api/autopilot/config";
|
||||
get.path = "/api/bus/autopilot";
|
||||
get.query["bucket"] = get_bucket(get_sia_config());
|
||||
|
||||
json config_data;
|
||||
@ -454,17 +510,18 @@ auto sia_provider::is_directory(const std::string &api_path, bool &exists) const
|
||||
|
||||
exists = false;
|
||||
|
||||
json object_list{};
|
||||
if (not get_object_list(utils::path::get_parent_api_path(api_path),
|
||||
object_list)) {
|
||||
return api_error::comm_error;
|
||||
json file_data{};
|
||||
auto res{get_object_info(api_path + '/', file_data)};
|
||||
if (res == api_error::item_not_found) {
|
||||
return api_error::success;
|
||||
}
|
||||
|
||||
exists = object_list.contains("entries") &&
|
||||
std::ranges::find_if(object_list.at("entries"),
|
||||
[&api_path](auto &&entry) -> bool {
|
||||
return entry.at("name") == (api_path + "/");
|
||||
}) != object_list.at("entries").end();
|
||||
if (res != api_error::success) {
|
||||
return res;
|
||||
}
|
||||
|
||||
exists =
|
||||
utils::string::ends_with(file_data.at("key").get<std::string>(), "/");
|
||||
return api_error::success;
|
||||
} catch (const std::exception &e) {
|
||||
utils::error::raise_api_path_error(
|
||||
@ -480,6 +537,7 @@ auto sia_provider::is_file(const std::string &api_path, bool &exists) const
|
||||
|
||||
try {
|
||||
exists = false;
|
||||
|
||||
if (api_path == "/") {
|
||||
return api_error::success;
|
||||
}
|
||||
@ -494,7 +552,8 @@ auto sia_provider::is_file(const std::string &api_path, bool &exists) const
|
||||
return res;
|
||||
}
|
||||
|
||||
exists = not file_data.contains("entries");
|
||||
exists = not utils::string::ends_with(
|
||||
file_data.at("key").get<std::string>(), "/");
|
||||
return api_error::success;
|
||||
} catch (const std::exception &e) {
|
||||
utils::error::raise_api_path_error(function_name, api_path, e,
|
||||
@ -558,8 +617,9 @@ auto sia_provider::read_file_bytes(const std::string &api_path,
|
||||
|
||||
try {
|
||||
curl::requests::http_get get{};
|
||||
get.path = "/api/worker/objects" + api_path;
|
||||
get.path = "/api/worker/object" + api_path;
|
||||
get.query["bucket"] = get_bucket(get_sia_config());
|
||||
get.headers["accept"] = "application/octet-stream";
|
||||
get.range = {{
|
||||
offset,
|
||||
offset + size - 1U,
|
||||
@ -576,6 +636,7 @@ auto sia_provider::read_file_bytes(const std::string &api_path,
|
||||
++idx) {
|
||||
long response_code{};
|
||||
const auto notify_retry = [&]() {
|
||||
fmt::println("{}", std::string(buffer.begin(), buffer.end()));
|
||||
if (response_code == 0) {
|
||||
utils::error::raise_api_path_error(
|
||||
function_name, api_path, api_error::comm_error,
|
||||
@ -621,7 +682,7 @@ auto sia_provider::remove_directory_impl(const std::string &api_path)
|
||||
|
||||
curl::requests::http_delete del{};
|
||||
del.allow_timeout = true;
|
||||
del.path = "/api/bus/objects" + api_path + "/";
|
||||
del.path = "/api/bus/object" + api_path + "/";
|
||||
del.query["bucket"] = get_bucket(get_sia_config());
|
||||
|
||||
std::string error_data;
|
||||
@ -657,7 +718,7 @@ auto sia_provider::remove_file_impl(const std::string &api_path) -> api_error {
|
||||
|
||||
curl::requests::http_delete del{};
|
||||
del.allow_timeout = true;
|
||||
del.path = "/api/bus/objects" + api_path;
|
||||
del.path = "/api/bus/object" + api_path;
|
||||
del.query["bucket"] = get_bucket(get_sia_config());
|
||||
|
||||
std::string error_data;
|
||||
@ -696,12 +757,12 @@ auto sia_provider::rename_file(const std::string &from_api_path,
|
||||
try {
|
||||
curl::requests::http_post post{};
|
||||
post.json = nlohmann::json({
|
||||
{"bucket", get_bucket(get_sia_config())},
|
||||
{"from", from_api_path},
|
||||
{"to", to_api_path},
|
||||
{"mode", "single"},
|
||||
});
|
||||
post.path = "/api/bus/objects/rename";
|
||||
post.query["bucket"] = get_bucket(get_sia_config());
|
||||
|
||||
std::string error_data;
|
||||
post.response_handler = [&error_data](auto &&data, long response_code) {
|
||||
@ -769,8 +830,9 @@ auto sia_provider::upload_file_impl(const std::string &api_path,
|
||||
REPERTORY_USES_FUNCTION_NAME();
|
||||
|
||||
curl::requests::http_put_file put_file{};
|
||||
put_file.path = "/api/worker/objects" + api_path;
|
||||
put_file.path = "/api/worker/object" + api_path;
|
||||
put_file.query["bucket"] = get_bucket(get_sia_config());
|
||||
put_file.headers["content-type"] = "application/octet-stream";
|
||||
put_file.source_path = source_path;
|
||||
|
||||
std::string error_data;
|
||||
|
@ -23,50 +23,38 @@
|
||||
#define REPERTORY_INCLUDE_CLI_CHECK_VERSION_HPP_
|
||||
|
||||
#include "app_config.hpp"
|
||||
#include "comm/curl/curl_comm.hpp"
|
||||
#include "providers/sia/sia_provider.hpp"
|
||||
#include "types/repertory.hpp"
|
||||
|
||||
namespace repertory::cli::actions {
|
||||
[[nodiscard]] inline auto
|
||||
check_version(std::vector<const char *> /* args */,
|
||||
const std::string & /* data_directory */,
|
||||
const provider_type & /* pt */, const std::string & /*unique_id*/,
|
||||
std::string /*user*/, std::string /*password*/) -> exit_code {
|
||||
auto ret = exit_code::success;
|
||||
[[nodiscard]] inline auto check_version(std::vector<const char *> /* args */,
|
||||
const std::string &data_directory,
|
||||
const provider_type &prov,
|
||||
const std::string & /*unique_id*/,
|
||||
std::string /*user*/,
|
||||
std::string /*password*/) -> exit_code {
|
||||
if (prov != provider_type::sia) {
|
||||
fmt::println("Success:\n\tNo specific version is required for {} providers",
|
||||
app_config::get_provider_display_name(prov));
|
||||
return exit_code::success;
|
||||
}
|
||||
|
||||
// TODO need to updated way to check version
|
||||
// if (not((pt == provider_type::remote) || (pt == provider_type::s3))) {
|
||||
// app_config config(pt, data_directory);
|
||||
// curl_comm comm(config);
|
||||
// json data, err;
|
||||
//
|
||||
// if (comm.get("/daemon/version", data, err) == api_error::success) {
|
||||
// const auto res = utils::compare_version_strings(
|
||||
// data["version"].get<std::string>(),
|
||||
// app_config::get_provider_minimum_version(pt));
|
||||
// if (res < 0) {
|
||||
// ret = exit_code::incompatible_version;
|
||||
// std::cerr << "Failed!" << std::endl;
|
||||
// std::cerr << " Actual: " << data["version"].get<std::string>()
|
||||
// << std::endl;
|
||||
// std::cerr << " Minimum: "
|
||||
// << app_config::get_provider_minimum_version(pt) <<
|
||||
// std::endl;
|
||||
// } else {
|
||||
// std::cout << "Success!" << std::endl;
|
||||
// std::cout << " Actual: " << data["version"].get<std::string>()
|
||||
// << std::endl;
|
||||
// std::cout << " Minimum: "
|
||||
// << app_config::get_provider_minimum_version(pt) <<
|
||||
// std::endl;
|
||||
// }
|
||||
// } else {
|
||||
// std::cerr << "Failed!" << std::endl;
|
||||
// std::cerr << err.dump(2) << std::endl;
|
||||
// ret = exit_code::communication_error;
|
||||
// }
|
||||
// }
|
||||
app_config config(prov, data_directory);
|
||||
curl_comm comm(config.get_host_config());
|
||||
sia_provider provider(config, comm);
|
||||
|
||||
return ret;
|
||||
std::string required_version;
|
||||
std::string returned_version;
|
||||
if (provider.check_version(required_version, returned_version)) {
|
||||
fmt::println("Success:\n\tRequired: {}\n\tActual: {}", required_version,
|
||||
returned_version);
|
||||
return exit_code::success;
|
||||
}
|
||||
|
||||
fmt::println("Failed:\n\tRequired: {}\n\tActual: {}", required_version,
|
||||
returned_version);
|
||||
return exit_code::incompatible_version;
|
||||
}
|
||||
} // namespace repertory::cli::actions
|
||||
|
||||
|
@ -36,6 +36,10 @@ private:
|
||||
const bool allow_rename_;
|
||||
|
||||
public:
|
||||
MOCK_METHOD(bool, check_version,
|
||||
(std::string & required_version, std::string &returned_version),
|
||||
(const, override));
|
||||
|
||||
MOCK_METHOD(api_error, create_directory,
|
||||
(const std::string &api_path, api_meta_map &meta), (override));
|
||||
|
||||
|
@ -638,7 +638,26 @@ static void get_file(const app_config &cfg, i_provider &provider) {
|
||||
EXPECT_EQ(std::size_t(46U), file.file_size);
|
||||
#endif
|
||||
EXPECT_STREQ(source_path.c_str(), file.source_path.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
create_file(provider, "/pt01.txt");
|
||||
|
||||
api_file file{};
|
||||
EXPECT_EQ(api_error::success, provider.get_file("/pt01.txt", file));
|
||||
|
||||
EXPECT_STREQ("/pt01.txt", file.api_path.c_str());
|
||||
EXPECT_STREQ("/", file.api_parent.c_str());
|
||||
EXPECT_LT(utils::time::get_time_now() - (utils::time::NANOS_PER_SECOND * 5U),
|
||||
file.accessed_date);
|
||||
EXPECT_LT(utils::time::get_time_now() - (utils::time::NANOS_PER_SECOND * 5U),
|
||||
file.changed_date);
|
||||
EXPECT_LT(utils::time::get_time_now() - (utils::time::NANOS_PER_SECOND * 5U),
|
||||
file.creation_date);
|
||||
EXPECT_LT(utils::time::get_time_now() - (utils::time::NANOS_PER_SECOND * 5U),
|
||||
file.modified_date);
|
||||
|
||||
EXPECT_EQ(api_error::success, provider.remove_file("/pt01.txt"));
|
||||
}
|
||||
|
||||
static void get_file_fails_if_file_not_found(i_provider &provider) {
|
||||
@ -664,7 +683,15 @@ static void get_file_fails_if_item_is_directory(const app_config &cfg,
|
||||
|
||||
api_file file{};
|
||||
EXPECT_EQ(api_error::directory_exists, provider.get_file(api_path, file));
|
||||
return;
|
||||
}
|
||||
|
||||
create_directory(provider, "/dir01");
|
||||
|
||||
api_file file{};
|
||||
EXPECT_EQ(api_error::directory_exists, provider.get_file("/dir01", file));
|
||||
|
||||
EXPECT_EQ(api_error::success, provider.remove_directory("/dir01"));
|
||||
}
|
||||
|
||||
static void get_file_list(const app_config &cfg, i_provider &provider) {
|
||||
@ -721,7 +748,6 @@ static void run_tests(const app_config &cfg, i_provider &provider) {
|
||||
|
||||
get_directory_item_count(cfg, provider);
|
||||
|
||||
// TODO continue here
|
||||
get_file(cfg, provider);
|
||||
get_file_fails_if_file_not_found(provider);
|
||||
get_file_fails_if_item_is_directory(cfg, provider);
|
||||
|
@ -42,6 +42,7 @@ done
|
||||
PROJECT_APP_LIST=()
|
||||
PROJECT_CMAKE_OPTS=""
|
||||
PROJECT_ENABLE_WIN32_LONG_PATH_NAMES=OFF
|
||||
PROJECT_ENABLE_V2_ERRORS=OFF
|
||||
PROJECT_IS_ALPINE=0
|
||||
PROJECT_IS_ARM64=0
|
||||
PROJECT_MINGW64_COPY_DEPENDENCIES=()
|
||||
@ -234,6 +235,7 @@ PROJECT_CMAKE_OPTS="-DPROJECT_BUILD_DIR=${PROJECT_BUILD_DIR} ${PROJECT_CMAKE_OPT
|
||||
PROJECT_CMAKE_OPTS="-DPROJECT_BUILD_SHARED_LIBS=${PROJECT_BUILD_SHARED_LIBS} ${PROJECT_CMAKE_OPTS}"
|
||||
PROJECT_CMAKE_OPTS="-DPROJECT_CMAKE_BUILD_TYPE=${PROJECT_CMAKE_BUILD_TYPE} ${PROJECT_CMAKE_OPTS}"
|
||||
PROJECT_CMAKE_OPTS="-DPROJECT_DIST_DIR=${PROJECT_DIST_DIR} ${PROJECT_CMAKE_OPTS}"
|
||||
PROJECT_CMAKE_OPTS="-DPROJECT_ENABLE_V2_ERRORS=${PROJECT_ENABLE_V2_ERRORS} ${PROJECT_CMAKE_OPTS}"
|
||||
PROJECT_CMAKE_OPTS="-DPROJECT_ENABLE_WIN32_LONG_PATH_NAMES=${PROJECT_ENABLE_WIN32_LONG_PATH_NAMES} ${PROJECT_CMAKE_OPTS}"
|
||||
PROJECT_CMAKE_OPTS="-DPROJECT_EXTERNAL_BUILD_ROOT=${PROJECT_EXTERNAL_BUILD_ROOT} ${PROJECT_CMAKE_OPTS}"
|
||||
PROJECT_CMAKE_OPTS="-DPROJECT_GIT_REV=${PROJECT_GIT_REV} ${PROJECT_CMAKE_OPTS}"
|
||||
@ -305,6 +307,7 @@ export PROJECT_COPYRIGHT
|
||||
export PROJECT_DESC
|
||||
export PROJECT_DIST_DIR
|
||||
export PROJECT_ENABLE_WIN32_LONG_PATH_NAMES
|
||||
export PROJECT_ENABLE_V2_ERRORS
|
||||
export PROJECT_FILE_PART
|
||||
export PROJECT_GIT_REV
|
||||
export PROJECT_IS_ALPINE
|
||||
@ -355,6 +358,7 @@ echo " Company name: ${PROJECT_COMPANY_NAME}"
|
||||
echo " Copyright: ${PROJECT_COPYRIGHT}"
|
||||
echo " Description: ${PROJECT_DESC}"
|
||||
echo " Dist dir: ${PROJECT_DIST_DIR}"
|
||||
echo " Enable v2 errors: ${PROJECT_ENABLE_V2_ERRORS}"
|
||||
echo " External build root: ${PROJECT_EXTERNAL_BUILD_ROOT}"
|
||||
echo " File part: ${PROJECT_FILE_PART}"
|
||||
echo " Is ARM64: ${PROJECT_IS_ARM64}"
|
||||
|
@ -25,12 +25,16 @@
|
||||
#include "utils/config.hpp"
|
||||
|
||||
namespace repertory::utils::error {
|
||||
[[nodiscard]] auto
|
||||
create_error_message(std::vector<std::string_view> items) -> std::string;
|
||||
[[nodiscard]] auto create_error_message(std::vector<std::string_view> items)
|
||||
-> std::string;
|
||||
|
||||
[[nodiscard]] auto
|
||||
create_exception(std::string_view function_name,
|
||||
std::vector<std::string_view> items) -> std::runtime_error;
|
||||
[[nodiscard]] auto create_error_message(std::string_view function_name,
|
||||
std::vector<std::string_view> items)
|
||||
-> std::string;
|
||||
|
||||
[[nodiscard]] auto create_exception(std::string_view function_name,
|
||||
std::vector<std::string_view> items)
|
||||
-> std::runtime_error;
|
||||
|
||||
struct i_exception_handler {
|
||||
virtual ~i_exception_handler() {}
|
||||
@ -40,6 +44,11 @@ struct i_exception_handler {
|
||||
auto operator=(const i_exception_handler &) noexcept = delete;
|
||||
auto operator=(i_exception_handler &&) noexcept = delete;
|
||||
|
||||
#if defined(PROJECT_ENABLE_V2_ERRORS)
|
||||
virtual void handle_debug(std::string_view function_name,
|
||||
std::string_view msg) const = 0;
|
||||
#endif // defined(PROJECT_ENABLE_V2_ERRORS)
|
||||
|
||||
virtual void handle_error(std::string_view function_name,
|
||||
std::string_view msg) const = 0;
|
||||
|
||||
@ -48,56 +57,107 @@ struct i_exception_handler {
|
||||
virtual void handle_exception(std::string_view function_name,
|
||||
const std::exception &ex) const = 0;
|
||||
|
||||
#if defined(PROJECT_ENABLE_V2_ERRORS)
|
||||
virtual void handle_info(std::string_view function_name,
|
||||
std::string_view msg) const = 0;
|
||||
|
||||
virtual void handle_trace(std::string_view function_name,
|
||||
std::string_view msg) const = 0;
|
||||
|
||||
virtual void handle_warn(std::string_view function_name,
|
||||
std::string_view msg) const = 0;
|
||||
#endif // defined(PROJECT_ENABLE_V2_ERRORS)
|
||||
|
||||
protected:
|
||||
i_exception_handler() = default;
|
||||
};
|
||||
|
||||
struct iostream_exception_handler final : i_exception_handler {
|
||||
void handle_error(std::string_view function_name,
|
||||
std::string_view msg) const override {
|
||||
std::cerr << create_error_message({
|
||||
function_name,
|
||||
msg,
|
||||
})
|
||||
<< std::endl;
|
||||
}
|
||||
struct iostream_exception_handler final : public i_exception_handler {
|
||||
#if defined(PROJECT_ENABLE_V2_ERRORS)
|
||||
void handle_debug(std::string_view function_name,
|
||||
std::string_view msg) const override;
|
||||
#endif // defined(PROJECT_ENABLE_V2_ERRORS)
|
||||
|
||||
void handle_exception(std::string_view function_name) const override {
|
||||
std::cerr << create_error_message({
|
||||
function_name,
|
||||
"exception",
|
||||
"unknown",
|
||||
})
|
||||
<< std::endl;
|
||||
}
|
||||
void handle_error(std::string_view function_name,
|
||||
std::string_view msg) const override;
|
||||
|
||||
void handle_exception(std::string_view function_name) const override;
|
||||
|
||||
void handle_exception(std::string_view function_name,
|
||||
const std::exception &ex) const override {
|
||||
std::cerr << create_error_message({
|
||||
function_name,
|
||||
"exception",
|
||||
(ex.what() == nullptr ? "unknown" : ex.what()),
|
||||
})
|
||||
<< std::endl;
|
||||
}
|
||||
};
|
||||
inline const iostream_exception_handler default_exception_handler{};
|
||||
const std::exception &ex) const override;
|
||||
|
||||
extern std::atomic<const i_exception_handler *> exception_handler;
|
||||
#if defined(PROJECT_ENABLE_V2_ERRORS)
|
||||
void handle_info(std::string_view function_name,
|
||||
std::string_view msg) const override;
|
||||
|
||||
void handle_trace(std::string_view function_name,
|
||||
std::string_view msg) const override;
|
||||
|
||||
void handle_warn(std::string_view function_name,
|
||||
std::string_view msg) const override;
|
||||
#endif // defined(PROJECT_ENABLE_V2_ERRORS)
|
||||
};
|
||||
|
||||
#if defined(PROJECT_ENABLE_SPDLOG) && defined(PROJECT_ENABLE_V2_ERRORS)
|
||||
struct spdlog_exception_handler final : public i_exception_handler {
|
||||
void handle_debug(std::string_view function_name,
|
||||
std::string_view msg) const override;
|
||||
|
||||
void handle_error(std::string_view function_name,
|
||||
std::string_view msg) const override;
|
||||
|
||||
void handle_exception(std::string_view function_name) const override;
|
||||
|
||||
void handle_exception(std::string_view function_name,
|
||||
const std::exception &ex) const override;
|
||||
|
||||
void handle_info(std::string_view function_name,
|
||||
std::string_view msg) const override;
|
||||
|
||||
void handle_trace(std::string_view function_name,
|
||||
std::string_view msg) const override;
|
||||
|
||||
void handle_warn(std::string_view function_name,
|
||||
std::string_view msg) const override;
|
||||
|
||||
private:
|
||||
iostream_exception_handler fallback{};
|
||||
};
|
||||
#endif // defined(PROJECT_ENABLE_SPDLOG) && defined(PROJECT_ENABLE_V2_ERRORS)
|
||||
|
||||
#if defined(PROJECT_ENABLE_SPDLOG) && defined(PROJECT_ENABLE_V2_ERRORS)
|
||||
inline const spdlog_exception_handler default_exception_handler{};
|
||||
#else // !defined(PROJECT_ENABLE_SPDLOG) || !defined(PROJECT_ENABLE_V2_ERRORS)
|
||||
inline const iostream_exception_handler default_exception_handler{};
|
||||
#endif // defined(PROJECT_ENABLE_SPDLOG) && defined(PROJECT_ENABLE_V2_ERRORS)
|
||||
|
||||
#if defined(PROJECT_ENABLE_TESTING)
|
||||
[[nodiscard]] inline auto
|
||||
get_exception_handler() -> const i_exception_handler * {
|
||||
extern std::atomic<const i_exception_handler *> exception_handler;
|
||||
|
||||
[[nodiscard]] inline auto get_exception_handler()
|
||||
-> const i_exception_handler * {
|
||||
return exception_handler;
|
||||
}
|
||||
#endif // defined(PROJECT_ENABLE_TESTING)
|
||||
|
||||
#if defined(PROJECT_ENABLE_V2_ERRORS)
|
||||
void handle_debug(std::string_view function_name, std::string_view msg);
|
||||
#endif // defined(PROJECT_ENABLE_V2_ERRORS)
|
||||
|
||||
void handle_error(std::string_view function_name, std::string_view msg);
|
||||
|
||||
void handle_exception(std::string_view function_name);
|
||||
|
||||
void handle_exception(std::string_view function_name, const std::exception &ex);
|
||||
|
||||
#if defined(PROJECT_ENABLE_V2_ERRORS)
|
||||
void handle_info(std::string_view function_name, std::string_view msg);
|
||||
|
||||
void handle_trace(std::string_view function_name, std::string_view msg);
|
||||
|
||||
void handle_warn(std::string_view function_name, std::string_view msg);
|
||||
#endif // defined(PROJECT_ENABLE_V2_ERRORS)
|
||||
|
||||
void set_exception_handler(const i_exception_handler *handler);
|
||||
} // namespace repertory::utils::error
|
||||
|
||||
|
@ -22,9 +22,6 @@
|
||||
#include "utils/error.hpp"
|
||||
|
||||
namespace repertory::utils::error {
|
||||
std::atomic<const i_exception_handler *> exception_handler{
|
||||
&default_exception_handler};
|
||||
|
||||
auto create_error_message(std::vector<std::string_view> items) -> std::string {
|
||||
std::stringstream stream{};
|
||||
for (std::size_t idx = 0U; idx < items.size(); ++idx) {
|
||||
@ -38,13 +35,30 @@ auto create_error_message(std::vector<std::string_view> items) -> std::string {
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
auto create_error_message(std::string_view function_name,
|
||||
std::vector<std::string_view> items) -> std::string {
|
||||
items.insert(items.begin(), function_name);
|
||||
return create_error_message(items);
|
||||
}
|
||||
|
||||
auto create_exception(std::string_view function_name,
|
||||
std::vector<std::string_view> items)
|
||||
-> std::runtime_error {
|
||||
items.insert(items.begin(), function_name);
|
||||
return std::runtime_error(create_error_message(items));
|
||||
return std::runtime_error(create_error_message(function_name, items));
|
||||
}
|
||||
|
||||
#if defined(PROJECT_ENABLE_V2_ERRORS)
|
||||
void handle_debug(std::string_view function_name, std::string_view msg) {
|
||||
const i_exception_handler *handler{exception_handler};
|
||||
if (handler != nullptr) {
|
||||
handler->handle_debug(function_name, msg);
|
||||
return;
|
||||
}
|
||||
|
||||
default_exception_handler.handle_debug(function_name, msg);
|
||||
}
|
||||
#endif // defined(PROJECT_ENABLE_V2_ERRORS)
|
||||
|
||||
void handle_error(std::string_view function_name, std::string_view msg) {
|
||||
const i_exception_handler *handler{exception_handler};
|
||||
if (handler != nullptr) {
|
||||
@ -76,6 +90,38 @@ void handle_exception(std::string_view function_name,
|
||||
default_exception_handler.handle_exception(function_name, ex);
|
||||
}
|
||||
|
||||
#if defined(PROJECT_ENABLE_V2_ERRORS)
|
||||
void handle_info(std::string_view function_name, std::string_view msg) {
|
||||
const i_exception_handler *handler{exception_handler};
|
||||
if (handler != nullptr) {
|
||||
handler->handle_info(function_name, msg);
|
||||
return;
|
||||
}
|
||||
|
||||
default_exception_handler.handle_info(function_name, msg);
|
||||
}
|
||||
|
||||
void handle_trace(std::string_view function_name, std::string_view msg) {
|
||||
const i_exception_handler *handler{exception_handler};
|
||||
if (handler != nullptr) {
|
||||
handler->handle_trace(function_name, msg);
|
||||
return;
|
||||
}
|
||||
|
||||
default_exception_handler.handle_trace(function_name, msg);
|
||||
}
|
||||
|
||||
void handle_warn(std::string_view function_name, std::string_view msg) {
|
||||
const i_exception_handler *handler{exception_handler};
|
||||
if (handler != nullptr) {
|
||||
handler->handle_warn(function_name, msg);
|
||||
return;
|
||||
}
|
||||
|
||||
default_exception_handler.handle_warn(function_name, msg);
|
||||
}
|
||||
#endif // defined(PROJECT_ENABLE_V2_ERRORS)
|
||||
|
||||
void set_exception_handler(const i_exception_handler *handler) {
|
||||
exception_handler = handler;
|
||||
}
|
||||
|
241
support/src/utils/error_handler.cpp
Normal file
241
support/src/utils/error_handler.cpp
Normal file
@ -0,0 +1,241 @@
|
||||
/*
|
||||
Copyright <2018-2025> <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 "utils/config.hpp"
|
||||
#include "utils/error.hpp"
|
||||
|
||||
namespace repertory::utils::error {
|
||||
std::atomic<const i_exception_handler *> exception_handler{
|
||||
&default_exception_handler};
|
||||
|
||||
#if defined(PROJECT_ENABLE_V2_ERRORS)
|
||||
void iostream_exception_handler::handle_debug(std::string_view function_name,
|
||||
std::string_view msg) const {
|
||||
std::cout << create_error_message({
|
||||
"debug",
|
||||
function_name,
|
||||
msg,
|
||||
})
|
||||
<< std::endl;
|
||||
}
|
||||
#endif // defined(PROJECT_ENABLE_V2_ERRORS)
|
||||
|
||||
void iostream_exception_handler::handle_error(std::string_view function_name,
|
||||
std::string_view msg) const {
|
||||
std::cerr << create_error_message({
|
||||
"error",
|
||||
function_name,
|
||||
msg,
|
||||
})
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
void iostream_exception_handler::handle_exception(
|
||||
std::string_view function_name) const {
|
||||
std::cerr << create_error_message({
|
||||
"error",
|
||||
function_name,
|
||||
"exception",
|
||||
"unknown",
|
||||
})
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
void iostream_exception_handler::handle_exception(
|
||||
std::string_view function_name, const std::exception &ex) const {
|
||||
std::cerr << create_error_message({
|
||||
"error",
|
||||
function_name,
|
||||
"exception",
|
||||
(ex.what() == nullptr ? "unknown" : ex.what()),
|
||||
})
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
#if defined(PROJECT_ENABLE_V2_ERRORS)
|
||||
void iostream_exception_handler::handle_info(std::string_view function_name,
|
||||
std::string_view msg) const {
|
||||
std::cout << create_error_message({
|
||||
"info",
|
||||
function_name,
|
||||
msg,
|
||||
})
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
void iostream_exception_handler::handle_trace(std::string_view function_name,
|
||||
std::string_view msg) const {
|
||||
std::cout << create_error_message({
|
||||
"trace",
|
||||
function_name,
|
||||
msg,
|
||||
})
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
void iostream_exception_handler::handle_warn(std::string_view function_name,
|
||||
std::string_view msg) const {
|
||||
std::cout << create_error_message({
|
||||
"warn",
|
||||
function_name,
|
||||
msg,
|
||||
})
|
||||
<< std::endl;
|
||||
}
|
||||
#endif // defined(PROJECT_ENABLE_V2_ERRORS)
|
||||
|
||||
#if defined(PROJECT_ENABLE_SPDLOG) && defined(PROJECT_ENABLE_V2_ERRORS)
|
||||
void spdlog_exception_handler::handle_debug(std::string_view function_name,
|
||||
std::string_view msg) const {
|
||||
auto console = spdlog::get("console");
|
||||
if (console) {
|
||||
console->debug(utils::error::create_error_message(function_name, {msg}));
|
||||
} else {
|
||||
fallback.handle_debug(function_name, msg);
|
||||
}
|
||||
|
||||
auto file = spdlog::get("file");
|
||||
if (not file) {
|
||||
return;
|
||||
}
|
||||
|
||||
file->debug(utils::error::create_error_message(function_name, {msg}));
|
||||
}
|
||||
|
||||
void spdlog_exception_handler::handle_error(std::string_view function_name,
|
||||
std::string_view msg) const {
|
||||
auto console = spdlog::get("console");
|
||||
if (console) {
|
||||
console->error(utils::error::create_error_message(function_name, {msg}));
|
||||
} else {
|
||||
fallback.handle_error(function_name, msg);
|
||||
}
|
||||
|
||||
auto file = spdlog::get("file");
|
||||
if (not file) {
|
||||
return;
|
||||
}
|
||||
|
||||
file->error(utils::error::create_error_message(function_name, {msg}));
|
||||
}
|
||||
|
||||
void spdlog_exception_handler::handle_exception(
|
||||
std::string_view function_name) const {
|
||||
auto console = spdlog::get("console");
|
||||
if (console) {
|
||||
console->error(utils::error::create_error_message(function_name,
|
||||
{
|
||||
"exception",
|
||||
"unknown exception",
|
||||
}));
|
||||
} else {
|
||||
fallback.handle_exception(function_name);
|
||||
}
|
||||
|
||||
auto file = spdlog::get("file");
|
||||
if (not file) {
|
||||
return;
|
||||
}
|
||||
|
||||
file->error(
|
||||
utils::error::create_error_message(function_name, {
|
||||
"exception",
|
||||
"unknown exception",
|
||||
}));
|
||||
}
|
||||
|
||||
void spdlog_exception_handler::handle_exception(
|
||||
std::string_view function_name, const std::exception &ex) const {
|
||||
auto console = spdlog::get("console");
|
||||
if (console) {
|
||||
console->error(utils::error::create_error_message(
|
||||
function_name, {
|
||||
"exception",
|
||||
(ex.what() == nullptr ? "unknown" : ex.what()),
|
||||
}));
|
||||
} else {
|
||||
fallback.handle_exception(function_name, ex);
|
||||
}
|
||||
|
||||
auto file = spdlog::get("file");
|
||||
if (not file) {
|
||||
return;
|
||||
}
|
||||
|
||||
file->error(utils::error::create_error_message(
|
||||
function_name, {
|
||||
"exception",
|
||||
(ex.what() == nullptr ? "unknown" : ex.what()),
|
||||
}));
|
||||
}
|
||||
|
||||
void spdlog_exception_handler::handle_info(std::string_view function_name,
|
||||
std::string_view msg) const {
|
||||
auto console = spdlog::get("console");
|
||||
if (console) {
|
||||
console->info(utils::error::create_error_message(function_name, {msg}));
|
||||
} else {
|
||||
fallback.handle_info(function_name, msg);
|
||||
}
|
||||
|
||||
auto file = spdlog::get("file");
|
||||
if (not file) {
|
||||
return;
|
||||
}
|
||||
|
||||
file->info(utils::error::create_error_message(function_name, {msg}));
|
||||
}
|
||||
|
||||
void spdlog_exception_handler::handle_trace(std::string_view function_name,
|
||||
std::string_view msg) const {
|
||||
auto console = spdlog::get("console");
|
||||
if (console) {
|
||||
console->trace(utils::error::create_error_message(function_name, {msg}));
|
||||
} else {
|
||||
fallback.handle_trace(function_name, msg);
|
||||
}
|
||||
|
||||
auto file = spdlog::get("file");
|
||||
if (not file) {
|
||||
return;
|
||||
}
|
||||
|
||||
file->trace(utils::error::create_error_message(function_name, {msg}));
|
||||
}
|
||||
|
||||
void spdlog_exception_handler::handle_warn(std::string_view function_name,
|
||||
std::string_view msg) const {
|
||||
auto console = spdlog::get("console");
|
||||
if (console) {
|
||||
console->warn(utils::error::create_error_message(function_name, {msg}));
|
||||
} else {
|
||||
fallback.handle_warn(function_name, msg);
|
||||
}
|
||||
|
||||
auto file = spdlog::get("file");
|
||||
if (not file) {
|
||||
return;
|
||||
}
|
||||
|
||||
file->warn(utils::error::create_error_message(function_name, {msg}));
|
||||
}
|
||||
#endif // defined(PROJECT_ENABLE_SPDLOG) && defined(PROJECT_ENABLE_V2_ERRORS)
|
||||
} // namespace repertory::utils::error
|
@ -41,8 +41,16 @@ auto change_to_process_directory() -> bool {
|
||||
|
||||
::GetModuleFileNameA(nullptr, file_name.data(),
|
||||
static_cast<DWORD>(file_name.size() - 1U));
|
||||
auto path = utils::path::strip_to_file_name(file_name.c_str());
|
||||
::SetCurrentDirectoryA(path.c_str());
|
||||
auto path = utils::path::get_parent_path(file_name.c_str());
|
||||
auto res = ::SetCurrentDirectoryA(path.c_str()) != 0;
|
||||
if (not res) {
|
||||
throw utils::error::create_exception(
|
||||
function_name, {
|
||||
"failed to set current directory",
|
||||
std::to_string(utils::get_last_error_code()),
|
||||
path,
|
||||
});
|
||||
}
|
||||
#else // !defined(_WIN32)
|
||||
std::string path;
|
||||
path.resize(PATH_MAX + 1);
|
||||
|
@ -29,15 +29,28 @@ TEST(utils_error, check_default_exception_handler) {
|
||||
EXPECT_TRUE(utils::error::get_exception_handler() != nullptr);
|
||||
if (&utils::error::default_exception_handler ==
|
||||
utils::error::get_exception_handler()) {
|
||||
#if defined(PROJECT_ENABLE_SPDLOG) && defined(PROJECT_ENABLE_V2_ERRORS)
|
||||
auto default_handler_is_spdlog =
|
||||
is_decay_equ<decltype(utils::error::default_exception_handler),
|
||||
utils::error::spdlog_exception_handler>;
|
||||
EXPECT_TRUE(default_handler_is_spdlog);
|
||||
#else // !defined(PROJECT_ENABLE_SPDLOG) || !defined(PROJECT_ENABLE_V2_ERRORS)
|
||||
auto default_handler_is_iostream =
|
||||
is_decay_equ<decltype(utils::error::default_exception_handler),
|
||||
utils::error::iostream_exception_handler>;
|
||||
EXPECT_TRUE(default_handler_is_iostream);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
TEST(utils_error, can_override_exception_handler) {
|
||||
struct my_exc_handler final : public utils::error::i_exception_handler {
|
||||
#if defined(PROJECT_ENABLE_V2_ERRORS)
|
||||
MOCK_METHOD(void, handle_debug,
|
||||
(std::string_view function_name, std::string_view msg),
|
||||
(const, override));
|
||||
#endif // defined(PROJECT_ENABLE_V2_ERRORS)
|
||||
|
||||
MOCK_METHOD(void, handle_error,
|
||||
(std::string_view function_name, std::string_view msg),
|
||||
(const, override));
|
||||
@ -48,11 +61,30 @@ TEST(utils_error, can_override_exception_handler) {
|
||||
MOCK_METHOD(void, handle_exception,
|
||||
(std::string_view function_name, const std::exception &ex),
|
||||
(const, override));
|
||||
|
||||
#if defined(PROJECT_ENABLE_V2_ERRORS)
|
||||
MOCK_METHOD(void, handle_info,
|
||||
(std::string_view function_name, std::string_view msg),
|
||||
(const, override));
|
||||
|
||||
MOCK_METHOD(void, handle_trace,
|
||||
(std::string_view function_name, std::string_view msg),
|
||||
(const, override));
|
||||
|
||||
MOCK_METHOD(void, handle_warn,
|
||||
(std::string_view function_name, std::string_view msg),
|
||||
(const, override));
|
||||
#endif // defined(PROJECT_ENABLE_V2_ERRORS)
|
||||
};
|
||||
|
||||
my_exc_handler handler{};
|
||||
utils::error::set_exception_handler(&handler);
|
||||
|
||||
#if defined(PROJECT_ENABLE_V2_ERRORS)
|
||||
EXPECT_CALL(handler, handle_debug("test_func", "debug")).WillOnce(Return());
|
||||
utils::error::handle_debug("test_func", "debug");
|
||||
#endif // defined(PROJECT_ENABLE_V2_ERRORS)
|
||||
|
||||
EXPECT_CALL(handler, handle_error("test_func", "error")).WillOnce(Return());
|
||||
utils::error::handle_error("test_func", "error");
|
||||
|
||||
@ -68,6 +100,17 @@ TEST(utils_error, can_override_exception_handler) {
|
||||
});
|
||||
utils::error::handle_exception("test_func_ex", ex);
|
||||
|
||||
#if defined(PROJECT_ENABLE_V2_ERRORS)
|
||||
EXPECT_CALL(handler, handle_info("test_func", "info")).WillOnce(Return());
|
||||
utils::error::handle_info("test_func", "info");
|
||||
|
||||
EXPECT_CALL(handler, handle_trace("test_func", "trace")).WillOnce(Return());
|
||||
utils::error::handle_trace("test_func", "trace");
|
||||
|
||||
EXPECT_CALL(handler, handle_warn("test_func", "warn")).WillOnce(Return());
|
||||
utils::error::handle_warn("test_func", "warn");
|
||||
#endif // defined(PROJECT_ENABLE_V2_ERRORS)
|
||||
|
||||
utils::error::set_exception_handler(&utils::error::default_exception_handler);
|
||||
}
|
||||
} // namespace repertory
|
||||
|
Reference in New Issue
Block a user