add remove mount capabilities to cli and ui #62

This commit is contained in:
2025-09-30 11:12:48 -05:00
parent f3719ea361
commit 4e6beed219
12 changed files with 73 additions and 55 deletions

View File

@@ -42,7 +42,7 @@ public:
~lock_data();
private:
std::string data_directory;
std::string data_directory_;
std::string mutex_id_;
private:
@@ -50,12 +50,12 @@ private:
int lock_status_{EWOULDBLOCK};
private:
[[nodiscard]] auto get_state_directory() -> std::string;
[[nodiscard]] auto get_lock_data_file() const -> std::string;
[[nodiscard]] auto get_lock_file() const -> std::string;
[[nodiscard]] auto get_state_directory() const -> std::string;
private:
[[nodiscard]] static auto wait_for_lock(int handle,
std::uint8_t retry_count = 30U)

View File

@@ -30,13 +30,13 @@ struct rpc_host_info {
std::string user;
};
enum class rpc_response_type {
enum class rpc_response_type : std::uint8_t {
success,
config_value_not_found,
http_error,
};
struct rpc_response {
struct rpc_response final {
rpc_response_type response_type;
json data;
};

View File

@@ -40,7 +40,8 @@ lock_data::lock_data(std::string data_directory, provider_type prov,
std::string_view unique_id)
: data_directory_(std::move(data_directory)),
mutex_id_(create_lock_id(prov, unique_id)) {
handle_ = open(get_lock_file().c_str(), O_CREAT | O_RDWR, S_IWUSR | S_IRUSR);
handle_ =
::open(get_lock_file().c_str(), O_CREAT | O_RDWR, S_IWUSR | S_IRUSR);
}
lock_data::~lock_data() { release(); }
@@ -72,7 +73,7 @@ auto lock_data::get_lock_file() const -> std::string {
}
auto lock_data::get_mount_state(json &mount_state) -> bool {
auto handle = open(get_lock_data_file().c_str(), O_RDWR, S_IWUSR | S_IRUSR);
auto handle = ::open(get_lock_data_file().c_str(), O_RDWR, S_IWUSR | S_IRUSR);
if (handle == -1) {
mount_state = {
{"Active", false},
@@ -93,14 +94,14 @@ auto lock_data::get_mount_state(json &mount_state) -> bool {
{"PID", -1},
};
}
flock(handle, LOCK_UN);
::flock(handle, LOCK_UN);
}
close(handle);
::close(handle);
return ret;
}
auto lock_data::get_state_directory() -> std::string {
auto lock_data::get_state_directory() const -> std::string {
return utils::path::absolute(data_directory_ + "/state");
}
@@ -130,7 +131,7 @@ void lock_data::release() {
flock(handle_, LOCK_UN);
}
close(handle_);
::close(handle_);
handle_ = -1;
}
@@ -139,7 +140,7 @@ auto lock_data::set_mount_state(bool active, std::string_view mount_location,
REPERTORY_USES_FUNCTION_NAME();
auto handle =
open(get_lock_data_file().c_str(), O_CREAT | O_RDWR, S_IWUSR | S_IRUSR);
::open(get_lock_data_file().c_str(), O_CREAT | O_RDWR, S_IWUSR | S_IRUSR);
if (handle == -1) {
return false;
}
@@ -172,10 +173,10 @@ auto lock_data::set_mount_state(bool active, std::string_view mount_location,
ret = true;
}
flock(handle, LOCK_UN);
::flock(handle, LOCK_UN);
}
close(handle);
::close(handle);
return ret;
}

View File

@@ -22,6 +22,8 @@
#ifndef REPERTORY_INCLUDE_CLI_ACTIONS_HPP_
#define REPERTORY_INCLUDE_CLI_ACTIONS_HPP_
#include "cli/common.hpp"
#include "cli/check_version.hpp"
#include "cli/display_config.hpp"
#include "cli/drive_information.hpp"

View File

@@ -49,15 +49,16 @@ check_version(const std::string &data_directory, provider_type prov,
auto client_version = utils::get_version_number(project_get_version());
auto res = client.check_version(client_version, min_version);
return cli::handle_error(
res == api_error::success || res == api_error::incompatible_version
? res
res == api_error::success ? exit_code::success
: res == api_error::incompatible_version
? exit_code::incompatible_version
: exit_code::communication_error,
fmt::format("required|{}|actual|{}", min_version, client_version));
}
if (prov != provider_type::sia) {
return cli::handle_error(
api_error::success,
exit_code::success,
fmt::format("version not required|provider|",
app_config::get_provider_display_name(prov)));
}
@@ -69,7 +70,7 @@ check_version(const std::string &data_directory, provider_type prov,
std::string required_version;
std::string returned_version;
if (provider.check_version(required_version, returned_version)) {
return cli::handle_error(api_error::success,
return cli::handle_error(exit_code::success,
fmt::format("required|{}|actual|{}",
required_version, returned_version));
}

View File

@@ -60,7 +60,7 @@ using remote_instance = repertory::remote_fuse::i_remote_instance;
namespace repertory::cli {
[[nodiscard]] inline auto handle_error(exit_code code, std::string_view msg)
-> exit_code {
fmt::println("{}", code);
fmt::println("{}", static_cast<std::int32_t>(code));
fmt::println("{}", msg);
return code;
}
@@ -68,7 +68,7 @@ namespace repertory::cli {
[[nodiscard]] inline auto handle_error(exit_code code,
rpc_response_type response_type,
std::string_view msg) -> exit_code {
fmt::println("{}", response_type);
fmt::println("{}", static_cast<std::uint8_t>(response_type));
fmt::println("{}", msg);
return code;
}

View File

@@ -41,7 +41,6 @@ namespace repertory::cli::actions {
if (lock_res == lock_result::success) {
app_config config(prov, data_directory);
const auto cfg = config.get_json();
return cli::handle_error(exit_code::success, cfg.dump(2));
}

View File

@@ -63,8 +63,8 @@ remove(std::vector<const char *> /* args */, const std::string &data_directory,
return cli::handle_error(
exit_code::remove_failed,
fmt::format("failed to remove provider|type|{}|id|{}|directory|",
app_config::get_provider_name(prov), unique_id),
data_directory);
app_config::get_provider_name(prov), unique_id,
data_directory));
}
} // namespace repertory::cli::actions

View File

@@ -31,7 +31,6 @@ unmount(std::vector<const char *> /* args */, const std::string &data_directory,
std::string user, std::string password) -> exit_code {
constexpr const std::uint8_t retry_count{30U};
auto ret{exit_code::success};
auto port{app_config::default_api_port(prov)};
utils::cli::get_api_authentication_data(user, password, port, prov,
data_directory);

View File

@@ -29,7 +29,6 @@
#include "utils/cli_utils.hpp"
#include "utils/error_utils.hpp"
#include "utils/file.hpp"
#include "utils/path.hpp"
namespace repertory::ui {
[[nodiscard]] auto ui_main(const std::vector<const char *> &args) -> int {

View File

@@ -539,6 +539,8 @@ void ui_server::handle_get_mount_location(const httplib::Request &req,
void ui_server::handle_get_mount_status(const httplib::Request &req,
httplib::Response &res) const {
REPERTORY_USES_FUNCTION_NAME();
auto name = req.get_param_value("name");
auto prov = provider_type_from_string(req.get_param_value("type"));
@@ -548,6 +550,14 @@ void ui_server::handle_get_mount_status(const httplib::Request &req,
}
auto lines = launch_process(prov, name, {"-status"});
if (lines.at(0U) != "0") {
throw utils::error::create_exception(function_name, {
"command failed",
lines.at(0U),
});
}
lines.erase(lines.begin());
auto result = nlohmann::json::parse(utils::string::join(lines, '\n'));
if (result.at("Location").get<std::string>().empty()) {

View File

@@ -23,86 +23,93 @@
#include "platform/platform.hpp"
namespace {
[[nodiscard]] auto get_lock_test_dir() -> std::string {
return repertory::utils::path::combine(repertory::test::get_test_output_dir(),
{"lock"});
}
} // namespace
namespace repertory {
TEST(lock_data_test, lock_and_unlock) {
{
lock_data l(provider_type::sia, "1");
EXPECT_EQ(lock_result::success, l.grab_lock());
lock_data lock(get_lock_test_dir(), provider_type::sia, "1");
EXPECT_EQ(lock_result::success, lock.grab_lock());
std::thread([]() {
lock_data l2(provider_type::sia, "1");
EXPECT_EQ(lock_result::locked, l2.grab_lock(10));
lock_data lock2(get_lock_test_dir(), provider_type::sia, "1");
EXPECT_EQ(lock_result::locked, lock2.grab_lock(10));
}).join();
}
std::thread([]() {
lock_data l(provider_type::sia, "1");
EXPECT_EQ(lock_result::success, l.grab_lock(10));
lock_data lock(get_lock_test_dir(), provider_type::sia, "1");
EXPECT_EQ(lock_result::success, lock.grab_lock(10));
}).join();
#if defined(_WIN32)
lock_data l2(provider_type::remote, "1");
EXPECT_EQ(lock_result::success, l2.grab_lock());
lock_data lock2(get_lock_test_dir(), provider_type::remote, "1");
EXPECT_EQ(lock_result::success, lock2.grab_lock());
lock_data l3(provider_type::remote, "2");
EXPECT_EQ(lock_result::success, l3.grab_lock());
lock_data lock3(get_lock_test_dir(), provider_type::remote, "2");
EXPECT_EQ(lock_result::success, lock3.grab_lock());
#endif
}
#if defined(_WIN32)
TEST(lock_data_test, set_and_unset_mount_state) {
lock_data l(provider_type::sia, "1");
EXPECT_TRUE(l.set_mount_state(true, "C:", 99));
lock_data lock(get_lock_test_dir(), provider_type::sia, "1");
EXPECT_TRUE(lock.set_mount_state(true, "C:", 99));
lock_data l2(provider_type::remote, "1");
EXPECT_TRUE(l2.set_mount_state(true, "D:", 97));
lock_data lock2(get_lock_test_dir(), provider_type::remote, "1");
EXPECT_TRUE(lock2.set_mount_state(true, "D:", 97));
lock_data l3(provider_type::remote, "2");
EXPECT_TRUE(l3.set_mount_state(true, "E:", 96));
lock_data lock3(get_lock_test_dir(), provider_type::remote, "2");
EXPECT_TRUE(lock3.set_mount_state(true, "E:", 96));
json mount_state;
EXPECT_TRUE(l.get_mount_state(mount_state));
EXPECT_TRUE(lock.get_mount_state(mount_state));
EXPECT_STREQ(R"({"Active":true,"Location":"C:","PID":99})",
mount_state.dump().c_str());
EXPECT_TRUE(l2.get_mount_state(mount_state));
EXPECT_TRUE(lock2.get_mount_state(mount_state));
EXPECT_STREQ(R"({"Active":true,"Location":"D:","PID":97})",
mount_state.dump().c_str());
EXPECT_TRUE(l3.get_mount_state(mount_state));
EXPECT_TRUE(lock3.get_mount_state(mount_state));
EXPECT_STREQ(R"({"Active":true,"Location":"E:","PID":96})",
mount_state.dump().c_str());
EXPECT_TRUE(l.set_mount_state(false, "C:", 99));
EXPECT_TRUE(l2.set_mount_state(false, "D:", 98));
EXPECT_TRUE(l3.set_mount_state(false, "E:", 97));
EXPECT_TRUE(lock.set_mount_state(false, "C:", 99));
EXPECT_TRUE(lock2.set_mount_state(false, "D:", 98));
EXPECT_TRUE(lock3.set_mount_state(false, "E:", 97));
EXPECT_TRUE(l.get_mount_state(mount_state));
EXPECT_TRUE(lock.get_mount_state(mount_state));
EXPECT_STREQ(R"({"Active":false,"Location":"","PID":-1})",
mount_state.dump().c_str());
EXPECT_TRUE(l2.get_mount_state(mount_state));
EXPECT_TRUE(lock2.get_mount_state(mount_state));
EXPECT_STREQ(R"({"Active":false,"Location":"","PID":-1})",
mount_state.dump().c_str());
EXPECT_TRUE(l3.get_mount_state(mount_state));
EXPECT_TRUE(lock3.get_mount_state(mount_state));
EXPECT_STREQ(R"({"Active":false,"Location":"","PID":-1})",
mount_state.dump().c_str());
}
#else
TEST(lock_data_test, set_and_unset_mount_state) {
lock_data l(provider_type::sia, "1");
EXPECT_TRUE(l.set_mount_state(true, "/mnt/1", 99));
lock_data lock(get_lock_test_dir(), provider_type::sia, "1");
EXPECT_TRUE(lock.set_mount_state(true, "/mnt/1", 99));
json mount_state;
EXPECT_TRUE(l.get_mount_state(mount_state));
EXPECT_TRUE(lock.get_mount_state(mount_state));
EXPECT_STREQ(R"({"Active":true,"Location":"/mnt/1","PID":99})",
mount_state.dump().c_str());
EXPECT_TRUE(l.set_mount_state(false, "/mnt/1", 99));
EXPECT_TRUE(lock.set_mount_state(false, "/mnt/1", 99));
EXPECT_TRUE(l.get_mount_state(mount_state));
EXPECT_TRUE(lock.get_mount_state(mount_state));
EXPECT_STREQ(R"({"Active":false,"Location":"","PID":-1})",
mount_state.dump().c_str());
}