Compare commits
6 Commits
1880c50fd8
...
de5eb1005c
Author | SHA1 | Date | |
---|---|---|---|
de5eb1005c | |||
fcaade316f | |||
4d60b39ea1 | |||
539abc1d5b | |||
3502bf2189 | |||
5f50e0204a |
@@ -15,6 +15,7 @@
|
||||
* \#46 [bug] Changes to maximum cache size should be updated live
|
||||
* \#47 [bug] Windows-to-Linux remote mount is allowing directory rename when directory is not empty
|
||||
* \#48 [bug] Windows-to-Linux remote mount overlapped I/O is not detecting EOF for read operations
|
||||
* \#49 [ui] Implement provider test button
|
||||
|
||||
### Changes from v2.0.5-rc
|
||||
|
||||
|
@@ -53,9 +53,6 @@ private:
|
||||
std::optional<host_config> host_config_;
|
||||
std::optional<s3_config> s3_config_;
|
||||
|
||||
private:
|
||||
bool use_s3_path_style_{false};
|
||||
|
||||
public:
|
||||
[[nodiscard]] static auto create_curl() -> CURL *;
|
||||
|
||||
@@ -67,8 +64,7 @@ public:
|
||||
const host_config &cfg)
|
||||
-> std::string;
|
||||
|
||||
[[nodiscard]] static auto create_host_config(const s3_config &cfg,
|
||||
bool use_s3_path_style)
|
||||
[[nodiscard]] static auto create_host_config(const s3_config &cfg)
|
||||
-> host_config;
|
||||
|
||||
[[nodiscard]] static auto url_encode(CURL *curl, const std::string &data,
|
||||
@@ -237,8 +233,6 @@ public:
|
||||
}
|
||||
|
||||
public:
|
||||
void enable_s3_path_style(bool enable) override;
|
||||
|
||||
[[nodiscard]] auto make_request(const curl::requests::http_delete &del,
|
||||
long &response_code,
|
||||
stop_type &stop_requested) const
|
||||
|
@@ -34,28 +34,29 @@ struct i_http_comm {
|
||||
INTERFACE_SETUP(i_http_comm);
|
||||
|
||||
public:
|
||||
virtual void enable_s3_path_style(bool enable) = 0;
|
||||
|
||||
[[nodiscard]] virtual auto
|
||||
make_request(const curl::requests::http_delete &del, long &response_code,
|
||||
stop_type &stop_requested) const -> bool = 0;
|
||||
|
||||
[[nodiscard]] virtual auto
|
||||
make_request(const curl::requests::http_get &get, long &response_code,
|
||||
stop_type &stop_requested) const -> bool = 0;
|
||||
[[nodiscard]] virtual auto make_request(const curl::requests::http_get &get,
|
||||
long &response_code,
|
||||
stop_type &stop_requested) const
|
||||
-> bool = 0;
|
||||
|
||||
[[nodiscard]] virtual auto
|
||||
make_request(const curl::requests::http_head &head, long &response_code,
|
||||
stop_type &stop_requested) const -> bool = 0;
|
||||
[[nodiscard]] virtual auto make_request(const curl::requests::http_head &head,
|
||||
long &response_code,
|
||||
stop_type &stop_requested) const
|
||||
-> bool = 0;
|
||||
|
||||
[[nodiscard]] virtual auto
|
||||
make_request(const curl::requests::http_post &post, long &response_code,
|
||||
stop_type &stop_requested) const -> bool = 0;
|
||||
[[nodiscard]] virtual auto make_request(const curl::requests::http_post &post,
|
||||
long &response_code,
|
||||
stop_type &stop_requested) const
|
||||
-> bool = 0;
|
||||
|
||||
[[nodiscard]] virtual auto
|
||||
make_request(const curl::requests::http_put_file &put_file,
|
||||
long &response_code,
|
||||
stop_type &stop_requested) const -> bool = 0;
|
||||
long &response_code, stop_type &stop_requested) const
|
||||
-> bool = 0;
|
||||
};
|
||||
} // namespace repertory
|
||||
|
||||
|
@@ -283,11 +283,13 @@ enum class exit_code : std::int32_t {
|
||||
init_failed = -18,
|
||||
ui_mount_failed = -19,
|
||||
exception = -20,
|
||||
provider_offline = -21
|
||||
};
|
||||
|
||||
enum http_error_codes : std::int32_t {
|
||||
ok = 200,
|
||||
multiple_choices = 300,
|
||||
bad_request = 400,
|
||||
unauthorized = 401,
|
||||
not_found = 404,
|
||||
internal_error = 500,
|
||||
|
@@ -49,6 +49,7 @@ static const option password_option = {"-pw", "--password"};
|
||||
static const option remote_mount_option = {"-rm", "--remote_mount"};
|
||||
static const option set_option = {"-set", "--set"};
|
||||
static const option status_option = {"-status", "--status"};
|
||||
static const option test_option = {"-test", "--test"};
|
||||
static const option ui_option = {"-ui", "--ui"};
|
||||
static const option ui_port_option = {"-up", "--ui_port"};
|
||||
static const option unmount_option = {"-unmount", "--unmount"};
|
||||
@@ -77,6 +78,7 @@ static const std::vector<option> option_list = {
|
||||
remote_mount_option,
|
||||
set_option,
|
||||
status_option,
|
||||
test_option,
|
||||
ui_option,
|
||||
ui_port_option,
|
||||
unmount_option,
|
||||
|
@@ -102,8 +102,7 @@ auto curl_comm::reset_curl(CURL *curl_handle) -> CURL * {
|
||||
return curl_handle;
|
||||
}
|
||||
|
||||
auto curl_comm::create_host_config(const s3_config &cfg, bool use_s3_path_style)
|
||||
-> host_config {
|
||||
auto curl_comm::create_host_config(const s3_config &cfg) -> host_config {
|
||||
host_config host_cfg{};
|
||||
host_cfg.api_password = cfg.secret_key;
|
||||
host_cfg.api_user = cfg.access_key;
|
||||
@@ -118,70 +117,61 @@ auto curl_comm::create_host_config(const s3_config &cfg, bool use_s3_path_style)
|
||||
}
|
||||
}
|
||||
|
||||
if (not use_s3_path_style) {
|
||||
if (not cfg.use_path_style) {
|
||||
host_cfg.host_name_or_ip = cfg.bucket + '.' + host_cfg.host_name_or_ip;
|
||||
}
|
||||
|
||||
host_cfg.protocol = cfg.url.substr(0U, pos);
|
||||
if (use_s3_path_style) {
|
||||
if (cfg.use_path_style) {
|
||||
host_cfg.path = '/' + cfg.bucket;
|
||||
}
|
||||
|
||||
return host_cfg;
|
||||
}
|
||||
|
||||
void curl_comm::enable_s3_path_style(bool enable) {
|
||||
use_s3_path_style_ = enable;
|
||||
}
|
||||
|
||||
auto curl_comm::make_request(const curl::requests::http_delete &del,
|
||||
long &response_code,
|
||||
stop_type &stop_requested) const -> bool {
|
||||
return make_request(
|
||||
s3_config_.has_value()
|
||||
? create_host_config(s3_config_.value(), use_s3_path_style_)
|
||||
: host_config_.value_or(host_config{}),
|
||||
del, response_code, stop_requested);
|
||||
return make_request(s3_config_.has_value()
|
||||
? create_host_config(s3_config_.value())
|
||||
: host_config_.value_or(host_config{}),
|
||||
del, response_code, stop_requested);
|
||||
}
|
||||
|
||||
auto curl_comm::make_request(const curl::requests::http_get &get,
|
||||
long &response_code,
|
||||
stop_type &stop_requested) const -> bool {
|
||||
return make_request(
|
||||
s3_config_.has_value()
|
||||
? create_host_config(s3_config_.value(), use_s3_path_style_)
|
||||
: host_config_.value_or(host_config{}),
|
||||
get, response_code, stop_requested);
|
||||
return make_request(s3_config_.has_value()
|
||||
? create_host_config(s3_config_.value())
|
||||
: host_config_.value_or(host_config{}),
|
||||
get, response_code, stop_requested);
|
||||
}
|
||||
|
||||
auto curl_comm::make_request(const curl::requests::http_head &head,
|
||||
long &response_code,
|
||||
stop_type &stop_requested) const -> bool {
|
||||
return make_request(
|
||||
s3_config_.has_value()
|
||||
? create_host_config(s3_config_.value(), use_s3_path_style_)
|
||||
: host_config_.value_or(host_config{}),
|
||||
head, response_code, stop_requested);
|
||||
return make_request(s3_config_.has_value()
|
||||
? create_host_config(s3_config_.value())
|
||||
: host_config_.value_or(host_config{}),
|
||||
head, response_code, stop_requested);
|
||||
}
|
||||
|
||||
auto curl_comm::make_request(const curl::requests::http_post &post,
|
||||
long &response_code,
|
||||
stop_type &stop_requested) const -> bool {
|
||||
return make_request(
|
||||
s3_config_.has_value()
|
||||
? create_host_config(s3_config_.value(), use_s3_path_style_)
|
||||
: host_config_.value_or(host_config{}),
|
||||
post, response_code, stop_requested);
|
||||
return make_request(s3_config_.has_value()
|
||||
? create_host_config(s3_config_.value())
|
||||
: host_config_.value_or(host_config{}),
|
||||
post, response_code, stop_requested);
|
||||
}
|
||||
|
||||
auto curl_comm::make_request(const curl::requests::http_put_file &put_file,
|
||||
long &response_code,
|
||||
stop_type &stop_requested) const -> bool {
|
||||
return make_request(
|
||||
s3_config_.has_value()
|
||||
? create_host_config(s3_config_.value(), use_s3_path_style_)
|
||||
: host_config_.value_or(host_config{}),
|
||||
put_file, response_code, stop_requested);
|
||||
return make_request(s3_config_.has_value()
|
||||
? create_host_config(s3_config_.value())
|
||||
: host_config_.value_or(host_config{}),
|
||||
put_file, response_code, stop_requested);
|
||||
}
|
||||
|
||||
auto curl_comm::url_encode(CURL *curl, const std::string &data,
|
||||
|
@@ -57,7 +57,7 @@ namespace {
|
||||
|
||||
namespace repertory {
|
||||
s3_provider::s3_provider(app_config &config, i_http_comm &comm)
|
||||
: base_provider(config, comm) {}
|
||||
: base_provider(config, comm), s3_config_(config.get_s3_config()) {}
|
||||
|
||||
auto s3_provider::add_if_not_found(api_file &file,
|
||||
const std::string &object_name) const
|
||||
@@ -793,8 +793,18 @@ auto s3_provider::is_file(const std::string &api_path, bool &exists) const
|
||||
}
|
||||
|
||||
auto s3_provider::is_online() const -> bool {
|
||||
// TODO implement this
|
||||
return true;
|
||||
REPERTORY_USES_FUNCTION_NAME();
|
||||
|
||||
try {
|
||||
std::string token;
|
||||
std::string response_data;
|
||||
long response_code{};
|
||||
return get_object_list(response_data, response_code, "/", "", token);
|
||||
} catch (const std::exception &e) {
|
||||
utils::error::raise_error(function_name, e, "exception occurred");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
auto s3_provider::read_file_bytes(const std::string &api_path, std::size_t size,
|
||||
@@ -1063,8 +1073,6 @@ auto s3_provider::start(api_item_added_callback api_item_added,
|
||||
|
||||
event_system::instance().raise<service_start_begin>(function_name,
|
||||
"s3_provider");
|
||||
s3_config_ = get_config().get_s3_config();
|
||||
get_comm().enable_s3_path_style(s3_config_.use_path_style);
|
||||
auto ret = base_provider::start(api_item_added, mgr);
|
||||
event_system::instance().raise<service_start_end>(function_name,
|
||||
"s3_provider");
|
||||
|
@@ -36,6 +36,7 @@
|
||||
#include "cli/pinned_status.hpp"
|
||||
#include "cli/set.hpp"
|
||||
#include "cli/status.hpp"
|
||||
#include "cli/test.hpp"
|
||||
#include "cli/ui.hpp"
|
||||
#include "cli/unmount.hpp"
|
||||
#include "cli/unpin_file.hpp"
|
||||
@@ -48,7 +49,7 @@ using action = std::function<exit_code(
|
||||
|
||||
struct option_hasher {
|
||||
auto operator()(const utils::cli::option &opt) const -> std::size_t {
|
||||
return std::hash<std::string>()(opt[0U] + '|' + opt[1U]);
|
||||
return std::hash<std::string>()(opt.at(0U) + '|' + opt.at(1U));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -71,6 +72,7 @@ static const std::unordered_map<utils::cli::option, action, option_hasher>
|
||||
cli::actions::pinned_status},
|
||||
{utils::cli::options::set_option, cli::actions::set},
|
||||
{utils::cli::options::status_option, cli::actions::status},
|
||||
{utils::cli::options::test_option, cli::actions::test},
|
||||
{utils::cli::options::ui_option, cli::actions::ui},
|
||||
{utils::cli::options::unmount_option, cli::actions::unmount},
|
||||
{utils::cli::options::unpin_file_option, cli::actions::unpin_file},
|
||||
|
@@ -44,12 +44,12 @@ namespace repertory::cli::actions {
|
||||
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,
|
||||
fmt::println("0\nSuccess:\n\tRequired: {}\n\tActual: {}", required_version,
|
||||
returned_version);
|
||||
return exit_code::success;
|
||||
}
|
||||
|
||||
fmt::println("Failed:\n\tRequired: {}\n\tActual: {}", required_version,
|
||||
fmt::println("1\nFailed:\n\tRequired: {}\n\tActual: {}", required_version,
|
||||
returned_version);
|
||||
return exit_code::incompatible_version;
|
||||
}
|
||||
|
45
repertory/repertory/include/cli/test.hpp
Normal file
45
repertory/repertory/include/cli/test.hpp
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
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_CLI_TEST_HPP_
|
||||
#define REPERTORY_INCLUDE_CLI_TEST_HPP_
|
||||
|
||||
#include "cli/common.hpp"
|
||||
|
||||
namespace repertory::cli::actions {
|
||||
[[nodiscard]] inline auto
|
||||
test(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 {
|
||||
app_config config(prov, data_directory);
|
||||
if (prov == provider_type::remote) {
|
||||
return exit_code::provider_offline;
|
||||
}
|
||||
|
||||
auto provider{create_provider(prov, config)};
|
||||
auto is_online{provider->is_online()};
|
||||
fmt::println("{}\nProvider is {}!", utils::string::from_bool(is_online),
|
||||
is_online ? "online" : "offline");
|
||||
return is_online ? exit_code::success : exit_code::provider_offline;
|
||||
}
|
||||
} // namespace repertory::cli::actions
|
||||
|
||||
#endif // REPERTORY_INCLUDE_CLI_TEST_HPP_
|
@@ -69,11 +69,16 @@ private:
|
||||
std::condition_variable nonce_notify_;
|
||||
std::unique_ptr<std::thread> nonce_thread_;
|
||||
stop_type stop_requested{false};
|
||||
mutable std::mutex test_mtx_;
|
||||
|
||||
private:
|
||||
[[nodiscard]] auto data_directory_exists(provider_type prov,
|
||||
std::string_view name) const -> bool;
|
||||
|
||||
void
|
||||
generate_config(provider_type prov, std::string_view name, const json &cfg,
|
||||
std::optional<std::string> data_dir = std::nullopt) const;
|
||||
|
||||
static void handle_get_available_locations(httplib::Response &res);
|
||||
|
||||
void handle_get_mount(const httplib::Request &req,
|
||||
@@ -91,6 +96,9 @@ private:
|
||||
|
||||
void handle_get_settings(httplib::Response &res) const;
|
||||
|
||||
void handle_get_test(const httplib::Request &req,
|
||||
httplib::Response &res) const;
|
||||
|
||||
void handle_post_add_mount(const httplib::Request &req,
|
||||
httplib::Response &res) const;
|
||||
|
||||
@@ -113,7 +121,8 @@ private:
|
||||
void removed_expired_nonces();
|
||||
|
||||
void set_key_value(provider_type prov, std::string_view name,
|
||||
std::string_view key, std::string_view value) const;
|
||||
std::string_view key, std::string_view value,
|
||||
std::optional<std::string> data_dir = std::nullopt) const;
|
||||
};
|
||||
} // namespace repertory::ui
|
||||
|
||||
|
@@ -98,6 +98,7 @@ namespace {
|
||||
|
||||
return std::string{value};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace repertory::ui {
|
||||
@@ -200,6 +201,9 @@ handlers::handlers(mgmt_app_config *config, httplib::Server *server)
|
||||
handle_get_settings(res);
|
||||
});
|
||||
|
||||
server->Get("/api/v1/test",
|
||||
[this](auto &&req, auto &&res) { handle_get_test(req, res); });
|
||||
|
||||
server->Post("/api/v1/add_mount", [this](auto &&req, auto &&res) {
|
||||
handle_post_add_mount(req, res);
|
||||
});
|
||||
@@ -308,6 +312,46 @@ auto handlers::data_directory_exists(provider_type prov,
|
||||
return ret;
|
||||
}
|
||||
|
||||
void handlers::generate_config(provider_type prov, std::string_view name,
|
||||
const json &cfg,
|
||||
std::optional<std::string> data_dir) const {
|
||||
std::map<std::string, std::string> values{};
|
||||
for (const auto &[key, value] : cfg.items()) {
|
||||
if (value.is_object()) {
|
||||
for (const auto &[key2, value2] : value.items()) {
|
||||
auto sub_key = fmt::format("{}.{}", key, key2);
|
||||
auto skip{false};
|
||||
auto decrypted = decrypt_value(
|
||||
config_, sub_key, value2.template get<std::string>(), skip);
|
||||
if (skip) {
|
||||
continue;
|
||||
}
|
||||
values[sub_key] = decrypted;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
auto skip{false};
|
||||
auto decrypted =
|
||||
decrypt_value(config_, key, value.template get<std::string>(), skip);
|
||||
if (skip) {
|
||||
continue;
|
||||
}
|
||||
values[key] = decrypted;
|
||||
}
|
||||
|
||||
if (data_dir.has_value()) {
|
||||
launch_process(prov, name, {"-dd", data_dir.value(), "-gc"});
|
||||
} else {
|
||||
launch_process(prov, name, {"-gc"});
|
||||
}
|
||||
|
||||
for (const auto &[key, value] : values) {
|
||||
set_key_value(prov, name, key, value, data_dir);
|
||||
}
|
||||
}
|
||||
|
||||
void handlers::handle_put_mount_location(const httplib::Request &req,
|
||||
httplib::Response &res) const {
|
||||
REPERTORY_USES_FUNCTION_NAME();
|
||||
@@ -367,7 +411,6 @@ void handlers::handle_get_mount(const httplib::Request &req,
|
||||
}
|
||||
|
||||
auto lines = launch_process(prov, name, {"-dc"});
|
||||
|
||||
if (lines.at(0U) != "0") {
|
||||
throw utils::error::create_exception(function_name, {
|
||||
"command failed",
|
||||
@@ -475,6 +518,26 @@ void handlers::handle_get_settings(httplib::Response &res) const {
|
||||
res.status = http_error_codes::ok;
|
||||
}
|
||||
|
||||
void handlers::handle_get_test(const httplib::Request &req,
|
||||
httplib::Response &res) const {
|
||||
unique_mutex_lock lock(test_mtx_);
|
||||
|
||||
auto name = req.get_param_value("name");
|
||||
auto prov = provider_type_from_string(req.get_param_value("type"));
|
||||
auto cfg = nlohmann::json::parse(req.get_param_value("config"));
|
||||
|
||||
auto data_dir = utils::path::combine(
|
||||
utils::directory::temp(), {utils::file::create_temp_name("repertory")});
|
||||
|
||||
generate_config(prov, name, cfg, data_dir);
|
||||
|
||||
auto lines = launch_process(prov, name, {"-dd", data_dir, "-test"});
|
||||
res.status = lines.at(0U) == "0" ? http_error_codes::ok
|
||||
: http_error_codes::internal_error;
|
||||
|
||||
utils::file::directory{data_dir}.remove_recursively();
|
||||
}
|
||||
|
||||
void handlers::handle_post_add_mount(const httplib::Request &req,
|
||||
httplib::Response &res) const {
|
||||
auto name = req.get_param_value("name");
|
||||
@@ -485,38 +548,9 @@ void handlers::handle_post_add_mount(const httplib::Request &req,
|
||||
}
|
||||
|
||||
auto cfg = nlohmann::json::parse(req.get_param_value("config"));
|
||||
generate_config(prov, name, cfg);
|
||||
|
||||
std::map<std::string, std::string> values{};
|
||||
for (const auto &[key, value] : cfg.items()) {
|
||||
if (value.is_object()) {
|
||||
for (const auto &[key2, value2] : value.items()) {
|
||||
auto sub_key = fmt::format("{}.{}", key, key2);
|
||||
auto skip{false};
|
||||
auto decrypted = decrypt_value(
|
||||
config_, sub_key, value2.template get<std::string>(), skip);
|
||||
if (skip) {
|
||||
continue;
|
||||
}
|
||||
values[sub_key] = decrypted;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
auto skip{false};
|
||||
auto decrypted =
|
||||
decrypt_value(config_, key, value.template get<std::string>(), skip);
|
||||
if (skip) {
|
||||
continue;
|
||||
}
|
||||
values[key] = decrypted;
|
||||
}
|
||||
|
||||
launch_process(prov, name, {"-gc"});
|
||||
for (auto &[key, value] : values) {
|
||||
set_key_value(prov, name, key, value);
|
||||
}
|
||||
|
||||
launch_process(prov, name, {"-test"});
|
||||
res.status = http_error_codes::ok;
|
||||
}
|
||||
|
||||
@@ -743,9 +777,13 @@ void handlers::removed_expired_nonces() {
|
||||
}
|
||||
|
||||
void handlers::set_key_value(provider_type prov, std::string_view name,
|
||||
std::string_view key,
|
||||
std::string_view value) const {
|
||||
std::string_view key, std::string_view value,
|
||||
std::optional<std::string> data_dir) const {
|
||||
std::vector<std::string> args;
|
||||
if (data_dir.has_value()) {
|
||||
args.emplace_back("-dd");
|
||||
args.emplace_back(data_dir.value());
|
||||
}
|
||||
args.emplace_back("-set");
|
||||
args.emplace_back(key);
|
||||
args.emplace_back(value);
|
||||
|
@@ -30,8 +30,9 @@ TEST(curl_comm_test, can_create_s3_host_config) {
|
||||
config.bucket = "repertory";
|
||||
config.url = "https://s3.test.com";
|
||||
config.region = "any";
|
||||
config.use_path_style = false;
|
||||
|
||||
auto hc = curl_comm::create_host_config(config, false);
|
||||
auto hc = curl_comm::create_host_config(config);
|
||||
EXPECT_STREQ("https", hc.protocol.c_str());
|
||||
EXPECT_STREQ("repertory.s3.test.com", hc.host_name_or_ip.c_str());
|
||||
EXPECT_TRUE(hc.path.empty());
|
||||
@@ -42,8 +43,9 @@ TEST(curl_comm_test, can_create_s3_host_config_with_path_style) {
|
||||
config.bucket = "repertory";
|
||||
config.url = "https://s3.test.com";
|
||||
config.region = "any";
|
||||
config.use_path_style = true;
|
||||
|
||||
auto hc = curl_comm::create_host_config(config, true);
|
||||
auto hc = curl_comm::create_host_config(config);
|
||||
EXPECT_STREQ("https", hc.protocol.c_str());
|
||||
EXPECT_STREQ("s3.test.com", hc.host_name_or_ip.c_str());
|
||||
EXPECT_STREQ("/repertory", hc.path.c_str());
|
||||
@@ -55,8 +57,9 @@ TEST(curl_comm_test, can_create_s3_host_config_with_region) {
|
||||
config.url = "https://s3.test.com";
|
||||
config.region = "any";
|
||||
config.use_region_in_url = true;
|
||||
config.use_path_style = false;
|
||||
|
||||
auto hc = curl_comm::create_host_config(config, false);
|
||||
auto hc = curl_comm::create_host_config(config);
|
||||
EXPECT_STREQ("https", hc.protocol.c_str());
|
||||
EXPECT_STREQ("repertory.s3.any.test.com", hc.host_name_or_ip.c_str());
|
||||
EXPECT_TRUE(hc.path.empty());
|
||||
@@ -68,8 +71,9 @@ TEST(curl_comm_test, can_create_s3_host_config_with_region_and_path_style) {
|
||||
config.url = "https://s3.test.com";
|
||||
config.region = "any";
|
||||
config.use_region_in_url = true;
|
||||
config.use_path_style = true;
|
||||
|
||||
auto hc = curl_comm::create_host_config(config, true);
|
||||
auto hc = curl_comm::create_host_config(config);
|
||||
EXPECT_STREQ("https", hc.protocol.c_str());
|
||||
EXPECT_STREQ("s3.any.test.com", hc.host_name_or_ip.c_str());
|
||||
EXPECT_STREQ("/repertory", hc.path.c_str());
|
||||
|
@@ -30,6 +30,10 @@
|
||||
#include "utils/types/file/i_file.hpp"
|
||||
#include "utils/types/file/i_fs_item.hpp"
|
||||
|
||||
namespace repertory::utils::directory {
|
||||
[[nodiscard]] auto temp() -> std::string;
|
||||
}
|
||||
|
||||
namespace repertory::utils::file {
|
||||
[[nodiscard]] auto change_to_process_directory() -> bool;
|
||||
|
||||
@@ -37,13 +41,13 @@ namespace repertory::utils::file {
|
||||
[[nodiscard]] auto create_temp_name(std::string_view file_part) -> std::string;
|
||||
|
||||
// INFO: has test
|
||||
[[nodiscard]] auto
|
||||
create_temp_name(std::wstring_view file_part) -> std::wstring;
|
||||
[[nodiscard]] auto create_temp_name(std::wstring_view file_part)
|
||||
-> std::wstring;
|
||||
|
||||
// INFO: has test
|
||||
[[nodiscard]] inline auto
|
||||
directory_exists_in_path(std::string_view path,
|
||||
std::string_view sub_directory) -> bool;
|
||||
directory_exists_in_path(std::string_view path, std::string_view sub_directory)
|
||||
-> bool;
|
||||
|
||||
// INFO: has test
|
||||
[[nodiscard]] inline auto
|
||||
@@ -51,45 +55,46 @@ directory_exists_in_path(std::wstring_view path,
|
||||
std::wstring_view sub_directory) -> bool;
|
||||
|
||||
// INFO: has test
|
||||
[[nodiscard]] inline auto
|
||||
file_exists_in_path(std::string_view path, std::string_view file_name) -> bool;
|
||||
[[nodiscard]] inline auto file_exists_in_path(std::string_view path,
|
||||
std::string_view file_name)
|
||||
-> bool;
|
||||
|
||||
// INFO: has test
|
||||
[[nodiscard]] inline auto
|
||||
file_exists_in_path(std::wstring_view path,
|
||||
std::wstring_view file_name) -> bool;
|
||||
[[nodiscard]] inline auto file_exists_in_path(std::wstring_view path,
|
||||
std::wstring_view file_name)
|
||||
-> bool;
|
||||
|
||||
// INFO: has test
|
||||
[[nodiscard]] auto
|
||||
get_free_drive_space(std::string_view path) -> std::optional<std::uint64_t>;
|
||||
[[nodiscard]] auto get_free_drive_space(std::string_view path)
|
||||
-> std::optional<std::uint64_t>;
|
||||
|
||||
// INFO: has test
|
||||
[[nodiscard]] auto
|
||||
get_free_drive_space(std::wstring_view path) -> std::optional<std::uint64_t>;
|
||||
[[nodiscard]] auto get_free_drive_space(std::wstring_view path)
|
||||
-> std::optional<std::uint64_t>;
|
||||
|
||||
// INFO: has test
|
||||
[[nodiscard]] auto get_time(std::string_view path,
|
||||
time_type type) -> std::optional<std::uint64_t>;
|
||||
[[nodiscard]] auto get_time(std::string_view path, time_type type)
|
||||
-> std::optional<std::uint64_t>;
|
||||
|
||||
// INFO: has test
|
||||
[[nodiscard]] auto get_time(std::wstring_view path,
|
||||
time_type type) -> std::optional<std::uint64_t>;
|
||||
[[nodiscard]] auto get_time(std::wstring_view path, time_type type)
|
||||
-> std::optional<std::uint64_t>;
|
||||
|
||||
// INFO: has test
|
||||
[[nodiscard]] auto
|
||||
get_times(std::string_view path) -> std::optional<file_times>;
|
||||
[[nodiscard]] auto get_times(std::string_view path)
|
||||
-> std::optional<file_times>;
|
||||
|
||||
// INFO: has test
|
||||
[[nodiscard]] auto
|
||||
get_times(std::wstring_view path) -> std::optional<file_times>;
|
||||
[[nodiscard]] auto get_times(std::wstring_view path)
|
||||
-> std::optional<file_times>;
|
||||
|
||||
// INFO: has test
|
||||
[[nodiscard]] auto
|
||||
get_total_drive_space(std::string_view path) -> std::optional<std::uint64_t>;
|
||||
[[nodiscard]] auto get_total_drive_space(std::string_view path)
|
||||
-> std::optional<std::uint64_t>;
|
||||
|
||||
// INFO: has test
|
||||
[[nodiscard]] auto
|
||||
get_total_drive_space(std::wstring_view path) -> std::optional<std::uint64_t>;
|
||||
[[nodiscard]] auto get_total_drive_space(std::wstring_view path)
|
||||
-> std::optional<std::uint64_t>;
|
||||
|
||||
#if defined(PROJECT_ENABLE_LIBDSM)
|
||||
[[nodiscard]] auto
|
||||
@@ -97,20 +102,20 @@ smb_create_and_validate_relative_path(std::string_view smb_path,
|
||||
std::string_view rel_path) -> std::string;
|
||||
|
||||
// INFO: has test
|
||||
[[nodiscard]] auto
|
||||
smb_create_relative_path(std::string_view smb_path) -> std::string;
|
||||
[[nodiscard]] auto smb_create_relative_path(std::string_view smb_path)
|
||||
-> std::string;
|
||||
|
||||
// INFO: has test
|
||||
[[nodiscard]] auto
|
||||
smb_create_search_path(std::string_view smb_path) -> std::string;
|
||||
[[nodiscard]] auto smb_create_search_path(std::string_view smb_path)
|
||||
-> std::string;
|
||||
|
||||
// INFO: has test
|
||||
[[nodiscard]] auto
|
||||
smb_create_smb_path(std::string_view smb_path,
|
||||
std::string_view rel_path) -> std::string;
|
||||
[[nodiscard]] auto smb_create_smb_path(std::string_view smb_path,
|
||||
std::string_view rel_path)
|
||||
-> std::string;
|
||||
|
||||
[[nodiscard]] auto
|
||||
smb_get_parent_path(std::string_view smb_path) -> std::string;
|
||||
[[nodiscard]] auto smb_get_parent_path(std::string_view smb_path)
|
||||
-> std::string;
|
||||
|
||||
[[nodiscard]] auto smb_get_root_path(std::string_view smb_path) -> std::string;
|
||||
|
||||
@@ -139,27 +144,30 @@ read_json_file(std::string_view path, nlohmann::json &data,
|
||||
std::optional<std::string_view> password = std::nullopt) -> bool;
|
||||
|
||||
// INFO: has test
|
||||
[[nodiscard]] auto read_json_file(
|
||||
std::wstring_view path, nlohmann::json &data,
|
||||
std::optional<std::wstring_view> password = std::nullopt) -> bool;
|
||||
[[nodiscard]] auto
|
||||
read_json_file(std::wstring_view path, nlohmann::json &data,
|
||||
std::optional<std::wstring_view> password = std::nullopt)
|
||||
-> bool;
|
||||
|
||||
// INFO: has test
|
||||
[[nodiscard]] auto write_json_file(
|
||||
std::string_view path, const nlohmann::json &data,
|
||||
std::optional<std::string_view> password = std::nullopt) -> bool;
|
||||
[[nodiscard]] auto
|
||||
write_json_file(std::string_view path, const nlohmann::json &data,
|
||||
std::optional<std::string_view> password = std::nullopt)
|
||||
-> bool;
|
||||
|
||||
// INFO: has test
|
||||
[[nodiscard]] auto write_json_file(
|
||||
std::wstring_view path, const nlohmann::json &data,
|
||||
std::optional<std::wstring_view> password = std::nullopt) -> bool;
|
||||
[[nodiscard]] auto
|
||||
write_json_file(std::wstring_view path, const nlohmann::json &data,
|
||||
std::optional<std::wstring_view> password = std::nullopt)
|
||||
-> bool;
|
||||
#else // !defined(PROJECT_ENABLE_LIBSODIUM) && defined(PROJECT_ENABLE_BOOST)
|
||||
// INFO: has test
|
||||
[[nodiscard]] auto read_json_file(std::string_view path,
|
||||
nlohmann::json &data) -> bool;
|
||||
[[nodiscard]] auto read_json_file(std::string_view path, nlohmann::json &data)
|
||||
-> bool;
|
||||
|
||||
// INFO: has test
|
||||
[[nodiscard]] auto read_json_file(std::wstring_view path,
|
||||
nlohmann::json &data) -> bool;
|
||||
[[nodiscard]] auto read_json_file(std::wstring_view path, nlohmann::json &data)
|
||||
-> bool;
|
||||
|
||||
// INFO: has test
|
||||
[[nodiscard]] auto write_json_file(std::string_view path,
|
||||
|
52
support/src/utils/directory.cpp
Normal file
52
support/src/utils/directory.cpp
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
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/file.hpp"
|
||||
|
||||
#include "utils/common.hpp"
|
||||
#include "utils/error.hpp"
|
||||
#if defined(_WIN32)
|
||||
#include "utils/path.hpp"
|
||||
#endif // defined(_WIN32)
|
||||
|
||||
namespace repertory::utils::directory {
|
||||
auto temp() -> std::string {
|
||||
REPERTORY_USES_FUNCTION_NAME();
|
||||
|
||||
#if defined(_WIN32)
|
||||
auto ret{utils::get_environment_variable("TEMP")};
|
||||
if (ret.empty()) {
|
||||
ret = utils::path::combine(utils::get_environment_variable("LOCALAPPDATA"),
|
||||
{"Temp"});
|
||||
}
|
||||
#else // !defined(_WIN32)
|
||||
std::string ret{"/tmp"};
|
||||
#endif // defined(_WIN32)
|
||||
|
||||
if (not utils::file::directory{ret}.create_directory()) {
|
||||
utils::error::handle_error(function_name,
|
||||
utils::error::create_error_message(
|
||||
{"failed to create directory", ret}));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
} // namespace repertory::utils::directory
|
@@ -282,4 +282,27 @@ class Mount with ChangeNotifier {
|
||||
debugPrint('$e');
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> test() async {
|
||||
try {
|
||||
final auth = await _auth.createAuth();
|
||||
final response = await http.put(
|
||||
Uri.parse(
|
||||
Uri.encodeFull(
|
||||
'${getBaseUri()}/api/v1/test?auth=$auth&name=$name&type=$type&config=${jsonEncode(mountConfig.settings)}',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
if (response.statusCode == 401) {
|
||||
_auth.logoff();
|
||||
}
|
||||
|
||||
return (response.statusCode == 200);
|
||||
} catch (e) {
|
||||
debugPrint('$e');
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@@ -113,8 +113,8 @@ class _AddMountScreenState extends State<AddMountScreen> {
|
||||
),
|
||||
),
|
||||
),
|
||||
if (_mount != null) const SizedBox(height: constants.padding),
|
||||
if (_mount != null)
|
||||
if (_mount != null) ...[
|
||||
const SizedBox(height: constants.padding),
|
||||
Expanded(
|
||||
child: Card(
|
||||
margin: EdgeInsets.all(0.0),
|
||||
@@ -129,8 +129,7 @@ class _AddMountScreenState extends State<AddMountScreen> {
|
||||
),
|
||||
),
|
||||
),
|
||||
if (_mount != null) const SizedBox(height: constants.padding),
|
||||
if (_mount != null)
|
||||
const SizedBox(height: constants.padding),
|
||||
Row(
|
||||
children: [
|
||||
ElevatedButton.icon(
|
||||
@@ -189,16 +188,15 @@ class _AddMountScreenState extends State<AddMountScreen> {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
if (_mountType == 'Sia' || _mountType == 'S3') ...[
|
||||
const SizedBox(width: constants.padding),
|
||||
ElevatedButton.icon(
|
||||
label: const Text('Test'),
|
||||
icon: const Icon(Icons.check),
|
||||
onPressed: () async {},
|
||||
),
|
||||
],
|
||||
const SizedBox(width: constants.padding),
|
||||
ElevatedButton.icon(
|
||||
label: const Text('Test'),
|
||||
icon: const Icon(Icons.check),
|
||||
onPressed: _handleProviderTest,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
],
|
||||
);
|
||||
},
|
||||
@@ -234,6 +232,22 @@ class _AddMountScreenState extends State<AddMountScreen> {
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _handleProviderTest() async {
|
||||
if (_mount == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final success = await _mount!.test();
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
|
||||
displayErrorMessage(
|
||||
context,
|
||||
success ? "Success!" : "Provider settings are invalid!",
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void setState(VoidCallback fn) {
|
||||
if (!mounted) {
|
||||
|
Reference in New Issue
Block a user