v2.0.5-rc (#41)
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
Reviewed-on: #41
This commit is contained in:
@@ -43,8 +43,7 @@ public:
|
||||
[[nodiscard]] static auto default_remote_api_port(const provider_type &prov)
|
||||
-> std::uint16_t;
|
||||
|
||||
[[nodiscard]] static auto default_rpc_port(const provider_type &prov)
|
||||
-> std::uint16_t;
|
||||
[[nodiscard]] static auto default_rpc_port() -> std::uint16_t;
|
||||
|
||||
[[nodiscard]] static auto get_provider_display_name(const provider_type &prov)
|
||||
-> std::string;
|
||||
@@ -52,6 +51,8 @@ public:
|
||||
[[nodiscard]] static auto get_provider_name(const provider_type &prov)
|
||||
-> std::string;
|
||||
|
||||
[[nodiscard]] static auto get_root_data_directory() -> std::string;
|
||||
|
||||
public:
|
||||
[[nodiscard]] static auto get_stop_requested() -> bool;
|
||||
|
||||
@@ -71,7 +72,7 @@ public:
|
||||
|
||||
private:
|
||||
provider_type prov_;
|
||||
atomic<std::string> api_auth_;
|
||||
atomic<std::string> api_password_;
|
||||
std::atomic<std::uint16_t> api_port_;
|
||||
atomic<std::string> api_user_;
|
||||
std::atomic<bool> config_changed_;
|
||||
@@ -121,7 +122,7 @@ private:
|
||||
auto set_value(dest &dst, const source &src) -> bool;
|
||||
|
||||
public:
|
||||
[[nodiscard]] auto get_api_auth() const -> std::string;
|
||||
[[nodiscard]] auto get_api_password() const -> std::string;
|
||||
|
||||
[[nodiscard]] auto get_api_port() const -> std::uint16_t;
|
||||
|
||||
@@ -199,7 +200,7 @@ public:
|
||||
|
||||
void save();
|
||||
|
||||
void set_api_auth(const std::string &value);
|
||||
void set_api_password(const std::string &value);
|
||||
|
||||
void set_api_port(std::uint16_t value);
|
||||
|
||||
|
@@ -57,7 +57,7 @@ using json = nlohmann::json;
|
||||
inline constexpr const std::string_view REPERTORY = "repertory";
|
||||
inline constexpr const std::wstring_view REPERTORY_W = L"repertory";
|
||||
|
||||
inline constexpr const std::uint64_t REPERTORY_CONFIG_VERSION = 1ULL;
|
||||
inline constexpr const std::uint64_t REPERTORY_CONFIG_VERSION = 2ULL;
|
||||
inline constexpr const std::string_view REPERTORY_DATA_NAME = "repertory2";
|
||||
inline constexpr const std::string_view REPERTORY_MIN_REMOTE_VERSION = "2.0.0";
|
||||
|
||||
|
@@ -22,6 +22,13 @@
|
||||
#ifndef REPERTORY_INCLUDE_PLATFORM_PLATFORM_HPP_
|
||||
#define REPERTORY_INCLUDE_PLATFORM_PLATFORM_HPP_
|
||||
|
||||
#include "types/repertory.hpp"
|
||||
|
||||
namespace repertory {
|
||||
[[nodiscard]] auto create_lock_id(provider_type prov,
|
||||
std::string_view unique_id)->std::string;
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include "platform/win32_platform.hpp"
|
||||
#include "utils/windows.hpp"
|
||||
|
@@ -30,38 +30,45 @@ class i_provider;
|
||||
|
||||
class lock_data final {
|
||||
public:
|
||||
explicit lock_data(const provider_type &pt, std::string unique_id /*= ""*/);
|
||||
lock_data(provider_type prov, std::string_view unique_id);
|
||||
|
||||
lock_data();
|
||||
lock_data(const lock_data &) = delete;
|
||||
lock_data(lock_data &&) = delete;
|
||||
|
||||
auto operator=(const lock_data &) -> lock_data & = delete;
|
||||
auto operator=(lock_data &&) -> lock_data & = delete;
|
||||
|
||||
~lock_data();
|
||||
|
||||
private:
|
||||
const provider_type pt_;
|
||||
const std::string unique_id_;
|
||||
const std::string mutex_id_;
|
||||
int lock_fd_;
|
||||
int lock_status_ = EWOULDBLOCK;
|
||||
std::string mutex_id_;
|
||||
|
||||
private:
|
||||
int handle_{};
|
||||
int lock_status_{EWOULDBLOCK};
|
||||
|
||||
private:
|
||||
[[nodiscard]] static auto get_state_directory() -> std::string;
|
||||
|
||||
[[nodiscard]] static auto get_lock_data_file() -> std::string;
|
||||
[[nodiscard]] auto get_lock_data_file() const -> std::string;
|
||||
|
||||
[[nodiscard]] auto get_lock_file() -> std::string;
|
||||
[[nodiscard]] auto get_lock_file() const -> std::string;
|
||||
|
||||
private:
|
||||
[[nodiscard]] static auto
|
||||
wait_for_lock(int fd, std::uint8_t retry_count = 30u) -> int;
|
||||
[[nodiscard]] static auto wait_for_lock(int handle,
|
||||
std::uint8_t retry_count = 30U)
|
||||
-> int;
|
||||
|
||||
public:
|
||||
[[nodiscard]] auto get_mount_state(json &mount_state) -> bool;
|
||||
|
||||
[[nodiscard]] auto grab_lock(std::uint8_t retry_count = 30u) -> lock_result;
|
||||
[[nodiscard]] auto grab_lock(std::uint8_t retry_count = 30U) -> lock_result;
|
||||
|
||||
void release();
|
||||
|
||||
[[nodiscard]] auto set_mount_state(bool active,
|
||||
const std::string &mount_location,
|
||||
int pid) -> bool;
|
||||
std::string_view mount_location, int pid)
|
||||
-> bool;
|
||||
};
|
||||
|
||||
[[nodiscard]] auto create_meta_attributes(
|
||||
@@ -76,5 +83,5 @@ public:
|
||||
const api_file &file) -> api_error;
|
||||
} // namespace repertory
|
||||
|
||||
#endif // _WIN32
|
||||
#endif // !defined(_WIN32)
|
||||
#endif // REPERTORY_INCLUDE_PLATFORM_UNIXPLATFORM_HPP_
|
||||
|
@@ -23,7 +23,6 @@
|
||||
#define REPERTORY_INCLUDE_PLATFORM_WINPLATFORM_HPP_
|
||||
#if defined(_WIN32)
|
||||
|
||||
#include "app_config.hpp"
|
||||
#include "types/repertory.hpp"
|
||||
|
||||
namespace repertory {
|
||||
@@ -31,43 +30,32 @@ class i_provider;
|
||||
|
||||
class lock_data final {
|
||||
public:
|
||||
explicit lock_data(const provider_type &pt, std::string unique_id /*= ""*/)
|
||||
: pt_(pt),
|
||||
unique_id_(std::move(unique_id)),
|
||||
mutex_id_("repertory_" + app_config::get_provider_name(pt) + "_" +
|
||||
unique_id_),
|
||||
mutex_handle_(::CreateMutex(nullptr, FALSE, &mutex_id_[0u])) {}
|
||||
explicit lock_data(provider_type prov, std::string unique_id);
|
||||
lock_data(const lock_data &) = delete;
|
||||
lock_data(lock_data &&) = delete;
|
||||
|
||||
lock_data()
|
||||
: pt_(provider_type::sia),
|
||||
unique_id_(""),
|
||||
mutex_id_(""),
|
||||
mutex_handle_(INVALID_HANDLE_VALUE) {}
|
||||
~lock_data();
|
||||
|
||||
~lock_data() { release(); }
|
||||
auto operator=(const lock_data &) -> lock_data & = delete;
|
||||
auto operator=(lock_data &&) -> lock_data & = delete;
|
||||
|
||||
private:
|
||||
const provider_type pt_;
|
||||
const std::string unique_id_;
|
||||
const std::string mutex_id_;
|
||||
HANDLE mutex_handle_;
|
||||
DWORD mutex_state_ = WAIT_FAILED;
|
||||
std::string mutex_id_;
|
||||
HANDLE mutex_handle_{INVALID_HANDLE_VALUE};
|
||||
DWORD mutex_state_{WAIT_FAILED};
|
||||
|
||||
[[nodiscard]] auto get_current_mount_state(json &mount_state) -> bool;
|
||||
|
||||
public:
|
||||
[[nodiscard]] auto get_mount_state(const provider_type &pt,
|
||||
json &mount_state) -> bool;
|
||||
|
||||
[[nodiscard]] auto get_mount_state(json &mount_state) -> bool;
|
||||
|
||||
[[nodiscard]] auto get_unique_id() const -> std::string { return unique_id_; }
|
||||
|
||||
[[nodiscard]] auto grab_lock(std::uint8_t retry_count = 30) -> lock_result;
|
||||
[[nodiscard]] auto grab_lock(std::uint8_t retry_count = 30U) -> lock_result;
|
||||
|
||||
void release();
|
||||
|
||||
[[nodiscard]] auto set_mount_state(bool active,
|
||||
const std::string &mount_location,
|
||||
const std::int64_t &pid) -> bool;
|
||||
std::string_view mount_location,
|
||||
std::int64_t pid) -> bool;
|
||||
};
|
||||
|
||||
[[nodiscard]] auto create_meta_attributes(
|
||||
|
@@ -48,9 +48,9 @@ public:
|
||||
|
||||
[[nodiscard]] auto get_pinned_files() -> rpc_response;
|
||||
|
||||
[[nodiscard]] auto pin_file(const std::string &api_file) -> rpc_response;
|
||||
[[nodiscard]] auto pin_file(const std::string &api_path) -> rpc_response;
|
||||
|
||||
[[nodiscard]] auto pinned_status(const std::string &api_file) -> rpc_response;
|
||||
[[nodiscard]] auto pinned_status(const std::string &api_path) -> rpc_response;
|
||||
|
||||
[[nodiscard]] auto set_config_value_by_name(const std::string &name,
|
||||
const std::string &value)
|
||||
@@ -58,7 +58,7 @@ public:
|
||||
|
||||
[[nodiscard]] auto unmount() -> rpc_response;
|
||||
|
||||
[[nodiscard]] auto unpin_file(const std::string &api_file) -> rpc_response;
|
||||
[[nodiscard]] auto unpin_file(const std::string &api_path) -> rpc_response;
|
||||
};
|
||||
} // namespace repertory
|
||||
|
||||
|
82
repertory/librepertory/include/rpc/common.hpp
Normal file
82
repertory/librepertory/include/rpc/common.hpp
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
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_RPC_COMMON_HPP_
|
||||
#define REPERTORY_INCLUDE_RPC_COMMON_HPP_
|
||||
|
||||
#include "utils/base64.hpp"
|
||||
#include "utils/error_utils.hpp"
|
||||
#include "utils/string.hpp"
|
||||
|
||||
namespace repertory::rpc {
|
||||
[[nodiscard]] auto check_authorization(const auto &cfg,
|
||||
const httplib::Request &req) -> bool {
|
||||
REPERTORY_USES_FUNCTION_NAME();
|
||||
|
||||
if (cfg.get_api_password().empty() || cfg.get_api_user().empty()) {
|
||||
utils::error::raise_error(function_name,
|
||||
"authorization user or password is not set");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto authorization = req.get_header_value("Authorization");
|
||||
if (authorization.empty()) {
|
||||
utils::error::raise_error(function_name,
|
||||
"'Authorization' header is not set");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto auth_parts = utils::string::split(authorization, ' ', true);
|
||||
if (auth_parts.empty()) {
|
||||
utils::error::raise_error(function_name, "'Authorization' header is empty");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto auth_type = auth_parts[0U];
|
||||
if (auth_type != "Basic") {
|
||||
utils::error::raise_error(function_name,
|
||||
"authorization type is not 'Basic'");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto data = macaron::Base64::Decode(authorization.substr(6U));
|
||||
auto auth_str = std::string(data.begin(), data.end());
|
||||
|
||||
auto auth = utils::string::split(auth_str, ':', false);
|
||||
if (auth.size() < 2U) {
|
||||
utils::error::raise_error(function_name, "authorization data is not valid");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto user = auth.at(0U);
|
||||
auth.erase(auth.begin());
|
||||
|
||||
auto pwd = utils::string::join(auth, ':');
|
||||
if ((user != cfg.get_api_user()) || (pwd != cfg.get_api_password())) {
|
||||
utils::error::raise_error(function_name, "authorization failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace repertory::rpc
|
||||
|
||||
#endif // REPERTORY_INCLUDE_RPC_COMMON_HPP_
|
@@ -40,8 +40,6 @@ private:
|
||||
std::mutex start_stop_mutex_;
|
||||
|
||||
private:
|
||||
[[nodiscard]] auto check_authorization(const httplib::Request &req) -> bool;
|
||||
|
||||
void handle_get_config(const httplib::Request &req, httplib::Response &res);
|
||||
|
||||
void handle_get_config_value_by_name(const httplib::Request &req,
|
||||
|
@@ -23,7 +23,7 @@
|
||||
#define REPERTORY_INCLUDE_TYPES_REPERTORY_HPP_
|
||||
|
||||
namespace repertory {
|
||||
constexpr const auto default_api_auth_size{48U};
|
||||
constexpr const auto default_api_password_size{48U};
|
||||
constexpr const auto default_download_timeout_secs{30U};
|
||||
constexpr const auto default_eviction_delay_mins{1U};
|
||||
constexpr const auto default_high_freq_interval_secs{std::uint16_t{30U}};
|
||||
@@ -38,6 +38,7 @@ constexpr const auto default_retry_read_count{6U};
|
||||
constexpr const auto default_ring_buffer_file_size{512U};
|
||||
constexpr const auto default_task_wait_ms{100U};
|
||||
constexpr const auto default_timeout_ms{60000U};
|
||||
constexpr const auto default_ui_mgmt_port{std::uint16_t{30000U}};
|
||||
constexpr const auto max_ring_buffer_file_size{std::uint16_t(1024U)};
|
||||
constexpr const auto max_s3_object_name_length{1024U};
|
||||
constexpr const auto min_cache_size_bytes{
|
||||
@@ -280,6 +281,8 @@ enum class exit_code : std::int32_t {
|
||||
pin_failed = -16,
|
||||
unpin_failed = -17,
|
||||
init_failed = -18,
|
||||
ui_mount_failed = -19,
|
||||
exception = -20,
|
||||
};
|
||||
|
||||
enum http_error_codes : std::int32_t {
|
||||
@@ -304,6 +307,18 @@ enum class provider_type : std::size_t {
|
||||
unknown,
|
||||
};
|
||||
|
||||
[[nodiscard]] auto
|
||||
provider_type_from_string(std::string_view type,
|
||||
provider_type default_type = provider_type::unknown)
|
||||
-> provider_type;
|
||||
|
||||
[[nodiscard]] auto provider_type_to_string(provider_type type) -> std::string;
|
||||
|
||||
void clean_json_config(provider_type prov, nlohmann::json &data);
|
||||
|
||||
[[nodiscard]] auto clean_json_value(std::string_view name,
|
||||
std::string_view data) -> std::string;
|
||||
|
||||
#if defined(_WIN32)
|
||||
struct open_file_data final {
|
||||
PVOID directory_buffer{nullptr};
|
||||
@@ -452,7 +467,6 @@ using meta_provider_callback = std::function<void(directory_item &)>;
|
||||
|
||||
inline constexpr const auto JSON_ACCESS_KEY{"AccessKey"};
|
||||
inline constexpr const auto JSON_AGENT_STRING{"AgentString"};
|
||||
inline constexpr const auto JSON_API_AUTH{"ApiAuth"};
|
||||
inline constexpr const auto JSON_API_PARENT{"ApiParent"};
|
||||
inline constexpr const auto JSON_API_PASSWORD{"ApiPassword"};
|
||||
inline constexpr const auto JSON_API_PATH{"ApiPath"};
|
||||
@@ -487,6 +501,7 @@ inline constexpr const auto JSON_MAX_UPLOAD_COUNT{"MaxUploadCount"};
|
||||
inline constexpr const auto JSON_MED_FREQ_INTERVAL_SECS{
|
||||
"MedFreqIntervalSeconds"};
|
||||
inline constexpr const auto JSON_META{"Meta"};
|
||||
inline constexpr const auto JSON_MOUNT_LOCATIONS{"MountLocations"};
|
||||
inline constexpr const auto JSON_ONLINE_CHECK_RETRY_SECS{
|
||||
"OnlineCheckRetrySeconds"};
|
||||
inline constexpr const auto JSON_PATH{"Path"};
|
||||
|
@@ -49,6 +49,8 @@ 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 ui_option = {"-ui", "--ui"};
|
||||
static const option ui_port_option = {"-up", "--ui_port"};
|
||||
static const option unmount_option = {"-unmount", "--unmount"};
|
||||
static const option unpin_file_option = {"-uf", "--unpin_file"};
|
||||
static const option user_option = {"-us", "--user"};
|
||||
@@ -75,6 +77,8 @@ static const std::vector<option> option_list = {
|
||||
remote_mount_option,
|
||||
set_option,
|
||||
status_option,
|
||||
ui_option,
|
||||
ui_port_option,
|
||||
unmount_option,
|
||||
unpin_file_option,
|
||||
user_option,
|
||||
@@ -87,26 +91,27 @@ void get_api_authentication_data(std::string &user, std::string &password,
|
||||
std::uint16_t &port, const provider_type &prov,
|
||||
const std::string &data_directory);
|
||||
|
||||
[[nodiscard]] auto
|
||||
get_provider_type_from_args(std::vector<const char *> args) -> provider_type;
|
||||
[[nodiscard]] auto get_provider_type_from_args(std::vector<const char *> args)
|
||||
-> provider_type;
|
||||
|
||||
[[nodiscard]] auto has_option(std::vector<const char *> args,
|
||||
const std::string &option_name) -> bool;
|
||||
|
||||
[[nodiscard]] auto has_option(std::vector<const char *> args,
|
||||
const option &opt) -> bool;
|
||||
[[nodiscard]] auto has_option(std::vector<const char *> args, const option &opt)
|
||||
-> bool;
|
||||
|
||||
[[nodiscard]] auto parse_option(std::vector<const char *> args,
|
||||
const std::string &option_name,
|
||||
std::uint8_t count) -> std::vector<std::string>;
|
||||
|
||||
[[nodiscard]] auto parse_string_option(std::vector<const char *> args,
|
||||
const option &opt,
|
||||
std::string &value) -> exit_code;
|
||||
const option &opt, std::string &value)
|
||||
-> exit_code;
|
||||
|
||||
[[nodiscard]] auto
|
||||
parse_drive_options(std::vector<const char *> args, provider_type &prov,
|
||||
std::string &data_directory) -> std::vector<std::string>;
|
||||
[[nodiscard]] auto parse_drive_options(std::vector<const char *> args,
|
||||
provider_type &prov,
|
||||
std::string &data_directory)
|
||||
-> std::vector<std::string>;
|
||||
} // namespace repertory::utils::cli
|
||||
|
||||
#endif // REPERTORY_INCLUDE_UTILS_CLI_UTILS_HPP_
|
||||
|
@@ -66,8 +66,8 @@ void app_config::set_stop_requested() { stop_requested.store(true); }
|
||||
app_config::app_config(const provider_type &prov,
|
||||
std::string_view data_directory)
|
||||
: prov_(prov),
|
||||
api_auth_(utils::generate_random_string(default_api_auth_size)),
|
||||
api_port_(default_rpc_port(prov)),
|
||||
api_password_(utils::generate_random_string(default_api_password_size)),
|
||||
api_port_(default_rpc_port()),
|
||||
api_user_(std::string{REPERTORY}),
|
||||
config_changed_(false),
|
||||
download_timeout_secs_(default_download_timeout_secs),
|
||||
@@ -124,7 +124,7 @@ app_config::app_config(const provider_type &prov,
|
||||
}
|
||||
|
||||
value_get_lookup_ = {
|
||||
{JSON_API_AUTH, [this]() { return get_api_auth(); }},
|
||||
{JSON_API_PASSWORD, [this]() { return get_api_password(); }},
|
||||
{JSON_API_PORT, [this]() { return std::to_string(get_api_port()); }},
|
||||
{JSON_API_USER, [this]() { return get_api_user(); }},
|
||||
{JSON_DATABASE_TYPE,
|
||||
@@ -253,10 +253,10 @@ app_config::app_config(const provider_type &prov,
|
||||
|
||||
value_set_lookup_ = {
|
||||
{
|
||||
JSON_API_AUTH,
|
||||
JSON_API_PASSWORD,
|
||||
[this](const std::string &value) {
|
||||
set_api_auth(value);
|
||||
return get_api_auth();
|
||||
set_api_password(value);
|
||||
return get_api_password();
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -699,36 +699,37 @@ auto app_config::default_api_port(const provider_type &prov) -> std::uint16_t {
|
||||
return PROVIDER_API_PORTS.at(static_cast<std::size_t>(prov));
|
||||
}
|
||||
|
||||
auto app_config::default_data_directory(const provider_type &prov)
|
||||
-> std::string {
|
||||
auto app_config::get_root_data_directory() -> std::string {
|
||||
#if defined(_WIN32)
|
||||
auto data_directory =
|
||||
utils::path::combine(utils::get_local_app_data_directory(),
|
||||
{
|
||||
REPERTORY_DATA_NAME,
|
||||
app_config::get_provider_name(prov),
|
||||
});
|
||||
auto data_directory = utils::path::combine(
|
||||
utils::get_local_app_data_directory(), {
|
||||
REPERTORY_DATA_NAME,
|
||||
});
|
||||
#else // !defined(_WIN32)
|
||||
#if defined(__APPLE__)
|
||||
auto data_directory =
|
||||
utils::path::combine("~", {
|
||||
"Library",
|
||||
"Application Support",
|
||||
REPERTORY_DATA_NAME,
|
||||
app_config::get_provider_name(prov),
|
||||
});
|
||||
auto data_directory = utils::path::combine("~", {
|
||||
"Library",
|
||||
"Application Support",
|
||||
REPERTORY_DATA_NAME,
|
||||
});
|
||||
#else // !defined(__APPLE__)
|
||||
auto data_directory =
|
||||
utils::path::combine("~", {
|
||||
".local",
|
||||
REPERTORY_DATA_NAME,
|
||||
app_config::get_provider_name(prov),
|
||||
});
|
||||
auto data_directory = utils::path::combine("~", {
|
||||
".local",
|
||||
REPERTORY_DATA_NAME,
|
||||
});
|
||||
#endif // defined(__APPLE__)
|
||||
#endif // defined(_WIN32)
|
||||
return data_directory;
|
||||
}
|
||||
|
||||
auto app_config::default_data_directory(const provider_type &prov)
|
||||
-> std::string {
|
||||
return utils::path::combine(app_config::get_root_data_directory(),
|
||||
{
|
||||
app_config::get_provider_name(prov),
|
||||
});
|
||||
}
|
||||
|
||||
auto app_config::default_remote_api_port(const provider_type &prov)
|
||||
-> std::uint16_t {
|
||||
static const std::array<std::uint16_t,
|
||||
@@ -741,19 +742,12 @@ auto app_config::default_remote_api_port(const provider_type &prov)
|
||||
};
|
||||
return PROVIDER_REMOTE_PORTS.at(static_cast<std::size_t>(prov));
|
||||
}
|
||||
auto app_config::default_rpc_port(const provider_type &prov) -> std::uint16_t {
|
||||
static const std::array<std::uint16_t,
|
||||
static_cast<std::size_t>(provider_type::unknown)>
|
||||
PROVIDER_RPC_PORTS = {
|
||||
10000U,
|
||||
10010U,
|
||||
10100U,
|
||||
10002U,
|
||||
};
|
||||
return PROVIDER_RPC_PORTS.at(static_cast<std::size_t>(prov));
|
||||
}
|
||||
|
||||
auto app_config::get_api_auth() const -> std::string { return api_auth_; }
|
||||
auto app_config::default_rpc_port() -> std::uint16_t { return 10000U; }
|
||||
|
||||
auto app_config::get_api_password() const -> std::string {
|
||||
return api_password_;
|
||||
}
|
||||
|
||||
auto app_config::get_api_port() const -> std::uint16_t { return api_port_; }
|
||||
|
||||
@@ -814,7 +808,7 @@ auto app_config::get_host_config() const -> host_config { return host_config_; }
|
||||
|
||||
auto app_config::get_json() const -> json {
|
||||
json ret = {
|
||||
{JSON_API_AUTH, api_auth_},
|
||||
{JSON_API_PASSWORD, api_password_},
|
||||
{JSON_API_PORT, api_port_},
|
||||
{JSON_API_USER, api_user_},
|
||||
{JSON_DOWNLOAD_TIMEOUT_SECS, download_timeout_secs_},
|
||||
@@ -939,24 +933,18 @@ auto app_config::get_preferred_download_type() const -> download_type {
|
||||
auto app_config::get_provider_display_name(const provider_type &prov)
|
||||
-> std::string {
|
||||
static const std::array<std::string,
|
||||
static_cast<std::size_t>(provider_type::unknown)>
|
||||
static_cast<std::size_t>(provider_type::unknown) + 1U>
|
||||
PROVIDER_DISPLAY_NAMES = {
|
||||
"Sia",
|
||||
"Remote",
|
||||
"S3",
|
||||
"Encrypt",
|
||||
"Sia", "Remote", "S3", "Encrypt", "Unknown",
|
||||
};
|
||||
return PROVIDER_DISPLAY_NAMES.at(static_cast<std::size_t>(prov));
|
||||
}
|
||||
|
||||
auto app_config::get_provider_name(const provider_type &prov) -> std::string {
|
||||
static const std::array<std::string,
|
||||
static_cast<std::size_t>(provider_type::unknown)>
|
||||
static_cast<std::size_t>(provider_type::unknown) + 1U>
|
||||
PROVIDER_NAMES = {
|
||||
"sia",
|
||||
"remote",
|
||||
"s3",
|
||||
"encrypt",
|
||||
"sia", "remote", "s3", "encrypt", "unknown",
|
||||
};
|
||||
return PROVIDER_NAMES.at(static_cast<std::size_t>(prov));
|
||||
}
|
||||
@@ -1035,7 +1023,7 @@ auto app_config::load() -> bool {
|
||||
auto found{true};
|
||||
auto json_document = json::parse(json_text);
|
||||
|
||||
get_value(json_document, JSON_API_AUTH, api_auth_, found);
|
||||
get_value(json_document, JSON_API_PASSWORD, api_password_, found);
|
||||
get_value(json_document, JSON_API_PORT, api_port_, found);
|
||||
get_value(json_document, JSON_API_USER, api_user_, found);
|
||||
get_value(json_document, JSON_DATABASE_TYPE, db_type_, found);
|
||||
@@ -1092,6 +1080,13 @@ auto app_config::load() -> bool {
|
||||
set_value(max_cache_size_bytes_, default_max_cache_size_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
if (version_ == 2U) {
|
||||
if (json_document.contains("ApiAuth")) {
|
||||
api_password_ = json_document.at("ApiAuth").get<std::string>();
|
||||
}
|
||||
}
|
||||
|
||||
found = false;
|
||||
}
|
||||
|
||||
@@ -1130,8 +1125,8 @@ void app_config::save() {
|
||||
});
|
||||
}
|
||||
|
||||
void app_config::set_api_auth(const std::string &value) {
|
||||
set_value(api_auth_, value);
|
||||
void app_config::set_api_password(const std::string &value) {
|
||||
set_value(api_password_, value);
|
||||
}
|
||||
|
||||
void app_config::set_api_port(std::uint16_t value) {
|
||||
|
@@ -21,9 +21,8 @@
|
||||
*/
|
||||
#if !defined(_WIN32)
|
||||
|
||||
#include "platform/unix_platform.hpp"
|
||||
#include "platform/platform.hpp"
|
||||
|
||||
#include "app_config.hpp"
|
||||
#include "events/event_system.hpp"
|
||||
#include "events/types/filesystem_item_added.hpp"
|
||||
#include "providers/i_provider.hpp"
|
||||
@@ -36,61 +35,65 @@
|
||||
#include "utils/unix.hpp"
|
||||
|
||||
namespace repertory {
|
||||
lock_data::lock_data(const provider_type &pt, std::string unique_id /*= ""*/)
|
||||
: pt_(pt),
|
||||
unique_id_(std::move(unique_id)),
|
||||
mutex_id_("repertory_" + app_config::get_provider_name(pt) + "_" +
|
||||
unique_id_) {
|
||||
lock_fd_ = open(get_lock_file().c_str(), O_CREAT | O_RDWR, S_IWUSR | S_IRUSR);
|
||||
lock_data::lock_data(provider_type prov, std::string_view unique_id)
|
||||
: mutex_id_(create_lock_id(prov, unique_id)) {
|
||||
handle_ = open(get_lock_file().c_str(), O_CREAT | O_RDWR, S_IWUSR | S_IRUSR);
|
||||
}
|
||||
|
||||
lock_data::lock_data()
|
||||
: pt_(provider_type::sia), unique_id_(""), mutex_id_(""), lock_fd_(-1) {}
|
||||
lock_data::~lock_data() { release(); }
|
||||
|
||||
lock_data::~lock_data() {
|
||||
if (lock_fd_ != -1) {
|
||||
if (lock_status_ == 0) {
|
||||
unlink(get_lock_file().c_str());
|
||||
flock(lock_fd_, LOCK_UN);
|
||||
}
|
||||
|
||||
close(lock_fd_);
|
||||
}
|
||||
}
|
||||
|
||||
auto lock_data::get_lock_data_file() -> std::string {
|
||||
const auto dir = get_state_directory();
|
||||
auto lock_data::get_lock_data_file() const -> std::string {
|
||||
auto dir = get_state_directory();
|
||||
if (not utils::file::directory(dir).create_directory()) {
|
||||
throw startup_exception("failed to create directory|sp|" + dir + "|err|" +
|
||||
std::to_string(utils::get_last_error_code()));
|
||||
}
|
||||
|
||||
return utils::path::combine(
|
||||
dir, {"mountstate_" + std::to_string(getuid()) + ".json"});
|
||||
dir, {
|
||||
fmt::format("{}_{}.json", mutex_id_, getuid()),
|
||||
});
|
||||
}
|
||||
|
||||
auto lock_data::get_lock_file() -> std::string {
|
||||
const auto dir = get_state_directory();
|
||||
auto lock_data::get_lock_file() const -> std::string {
|
||||
auto dir = get_state_directory();
|
||||
if (not utils::file::directory(dir).create_directory()) {
|
||||
throw startup_exception("failed to create directory|sp|" + dir + "|err|" +
|
||||
std::to_string(utils::get_last_error_code()));
|
||||
}
|
||||
|
||||
return utils::path::combine(dir,
|
||||
{mutex_id_ + "_" + std::to_string(getuid())});
|
||||
return utils::path::combine(
|
||||
dir, {
|
||||
fmt::format("{}_{}.lock", mutex_id_, getuid()),
|
||||
});
|
||||
}
|
||||
|
||||
auto lock_data::get_mount_state(json &mount_state) -> bool {
|
||||
auto ret = false;
|
||||
auto fd =
|
||||
open(get_lock_data_file().c_str(), O_CREAT | O_RDWR, S_IWUSR | S_IRUSR);
|
||||
if (fd != -1) {
|
||||
if (wait_for_lock(fd) == 0) {
|
||||
ret = utils::file::read_json_file(get_lock_data_file(), mount_state);
|
||||
flock(fd, LOCK_UN);
|
||||
}
|
||||
auto handle = open(get_lock_data_file().c_str(), O_RDWR, S_IWUSR | S_IRUSR);
|
||||
if (handle == -1) {
|
||||
mount_state = {
|
||||
{"Active", false},
|
||||
{"Location", ""},
|
||||
{"PID", -1},
|
||||
};
|
||||
|
||||
close(fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
auto ret{false};
|
||||
if (wait_for_lock(handle) == 0) {
|
||||
ret = utils::file::read_json_file(get_lock_data_file(), mount_state);
|
||||
if (ret && mount_state.empty()) {
|
||||
mount_state = {
|
||||
{"Active", false},
|
||||
{"Location", ""},
|
||||
{"PID", -1},
|
||||
};
|
||||
}
|
||||
flock(handle, LOCK_UN);
|
||||
}
|
||||
|
||||
close(handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -98,25 +101,20 @@ auto lock_data::get_state_directory() -> std::string {
|
||||
#if defined(__APPLE__)
|
||||
return utils::path::absolute("~/Library/Application Support/" +
|
||||
std::string{REPERTORY_DATA_NAME} + "/state");
|
||||
#else
|
||||
#else // !defined(__APPLE__)
|
||||
return utils::path::absolute("~/.local/" + std::string{REPERTORY_DATA_NAME} +
|
||||
"/state");
|
||||
#endif
|
||||
#endif // defined(__APPLE__)
|
||||
}
|
||||
|
||||
auto lock_data::grab_lock(std::uint8_t retry_count) -> lock_result {
|
||||
REPERTORY_USES_FUNCTION_NAME();
|
||||
|
||||
if (lock_fd_ == -1) {
|
||||
if (handle_ == -1) {
|
||||
return lock_result::failure;
|
||||
}
|
||||
|
||||
lock_status_ = wait_for_lock(lock_fd_, retry_count);
|
||||
lock_status_ = wait_for_lock(handle_, retry_count);
|
||||
switch (lock_status_) {
|
||||
case 0:
|
||||
if (not set_mount_state(false, "", -1)) {
|
||||
utils::error::raise_error(function_name, "failed to set mount state");
|
||||
}
|
||||
return lock_result::success;
|
||||
case EWOULDBLOCK:
|
||||
return lock_result::locked;
|
||||
@@ -125,61 +123,72 @@ auto lock_data::grab_lock(std::uint8_t retry_count) -> lock_result {
|
||||
}
|
||||
}
|
||||
|
||||
auto lock_data::set_mount_state(bool active, const std::string &mount_location,
|
||||
void lock_data::release() {
|
||||
if (handle_ == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (lock_status_ == 0) {
|
||||
[[maybe_unused]] auto success{utils::file::file{get_lock_file()}.remove()};
|
||||
flock(handle_, LOCK_UN);
|
||||
}
|
||||
|
||||
close(handle_);
|
||||
handle_ = -1;
|
||||
}
|
||||
|
||||
auto lock_data::set_mount_state(bool active, std::string_view mount_location,
|
||||
int pid) -> bool {
|
||||
REPERTORY_USES_FUNCTION_NAME();
|
||||
|
||||
auto ret = false;
|
||||
auto handle =
|
||||
open(get_lock_data_file().c_str(), O_CREAT | O_RDWR, S_IWUSR | S_IRUSR);
|
||||
if (handle != -1) {
|
||||
if (wait_for_lock(handle) == 0) {
|
||||
const auto mount_id =
|
||||
app_config::get_provider_display_name(pt_) + unique_id_;
|
||||
json mount_state;
|
||||
if (not utils::file::read_json_file(get_lock_data_file(), mount_state)) {
|
||||
utils::error::raise_error(function_name,
|
||||
"failed to read mount state file|sp|" +
|
||||
get_lock_file());
|
||||
}
|
||||
if ((mount_state.find(mount_id) == mount_state.end()) ||
|
||||
(mount_state[mount_id].find("Active") ==
|
||||
mount_state[mount_id].end()) ||
|
||||
(mount_state[mount_id]["Active"].get<bool>() != active) ||
|
||||
(active && ((mount_state[mount_id].find("Location") ==
|
||||
mount_state[mount_id].end()) ||
|
||||
(mount_state[mount_id]["Location"].get<std::string>() !=
|
||||
mount_location)))) {
|
||||
const auto lines = utils::file::read_file_lines(get_lock_data_file());
|
||||
const auto txt = std::accumulate(
|
||||
lines.begin(), lines.end(), std::string(),
|
||||
[](auto &&val, auto &&line) -> auto { return val + line; });
|
||||
auto json_data = json::parse(txt.empty() ? "{}" : txt);
|
||||
json_data[mount_id] = {
|
||||
{"Active", active},
|
||||
{"Location", active ? mount_location : ""},
|
||||
{"PID", active ? pid : -1},
|
||||
};
|
||||
ret = utils::file::write_json_file(get_lock_data_file(), json_data);
|
||||
} else {
|
||||
ret = true;
|
||||
}
|
||||
if (handle == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
flock(handle, LOCK_UN);
|
||||
auto ret{false};
|
||||
if (wait_for_lock(handle) == 0) {
|
||||
json mount_state;
|
||||
if (not utils::file::read_json_file(get_lock_data_file(), mount_state)) {
|
||||
utils::error::raise_error(function_name,
|
||||
"failed to read mount state file|sp|" +
|
||||
get_lock_file());
|
||||
}
|
||||
if ((mount_state.find("Active") == mount_state.end()) ||
|
||||
(mount_state["Active"].get<bool>() != active) ||
|
||||
(active &&
|
||||
((mount_state.find("Location") == mount_state.end()) ||
|
||||
(mount_state["Location"].get<std::string>() != mount_location)))) {
|
||||
if (mount_location.empty() && not active) {
|
||||
ret = utils::file::file{get_lock_data_file()}.remove();
|
||||
} else {
|
||||
ret = utils::file::write_json_file(
|
||||
get_lock_data_file(),
|
||||
{
|
||||
{"Active", active},
|
||||
{"Location", active ? mount_location : ""},
|
||||
{"PID", active ? pid : -1},
|
||||
});
|
||||
}
|
||||
} else {
|
||||
ret = true;
|
||||
}
|
||||
|
||||
close(handle);
|
||||
flock(handle, LOCK_UN);
|
||||
}
|
||||
|
||||
close(handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
auto lock_data::wait_for_lock(int fd, std::uint8_t retry_count) -> int {
|
||||
static constexpr const std::uint32_t max_sleep = 100U;
|
||||
auto lock_data::wait_for_lock(int handle, std::uint8_t retry_count) -> int {
|
||||
static constexpr const std::uint32_t max_sleep{100U};
|
||||
|
||||
auto lock_status = EWOULDBLOCK;
|
||||
auto remain = static_cast<std::uint32_t>(retry_count * max_sleep);
|
||||
auto lock_status{EWOULDBLOCK};
|
||||
auto remain{static_cast<std::uint32_t>(retry_count * max_sleep)};
|
||||
while ((remain > 0) && (lock_status == EWOULDBLOCK)) {
|
||||
lock_status = flock(fd, LOCK_EX | LOCK_NB);
|
||||
lock_status = flock(handle, LOCK_EX | LOCK_NB);
|
||||
if (lock_status == -1) {
|
||||
lock_status = errno;
|
||||
if (lock_status == EWOULDBLOCK) {
|
||||
@@ -228,13 +237,13 @@ auto provider_meta_handler(i_provider &provider, bool directory,
|
||||
const api_file &file) -> api_error {
|
||||
REPERTORY_USES_FUNCTION_NAME();
|
||||
|
||||
const auto meta = create_meta_attributes(
|
||||
auto meta = create_meta_attributes(
|
||||
file.accessed_date,
|
||||
directory ? FILE_ATTRIBUTE_DIRECTORY : FILE_ATTRIBUTE_ARCHIVE,
|
||||
file.changed_date, file.creation_date, directory, getgid(), file.key,
|
||||
directory ? S_IFDIR | S_IRUSR | S_IWUSR | S_IXUSR
|
||||
: S_IFREG | S_IRUSR | S_IWUSR,
|
||||
file.modified_date, 0u, 0u, file.file_size, file.source_path, getuid(),
|
||||
file.modified_date, 0U, 0U, file.file_size, file.source_path, getuid(),
|
||||
file.modified_date);
|
||||
auto res = provider.set_item_meta(file.api_path, meta);
|
||||
if (res == api_error::success) {
|
||||
|
@@ -21,150 +21,171 @@
|
||||
*/
|
||||
#if defined(_WIN32)
|
||||
|
||||
#include "platform/win32_platform.hpp"
|
||||
#include "platform/platform.hpp"
|
||||
|
||||
#include "events/event_system.hpp"
|
||||
#include "events/types/filesystem_item_added.hpp"
|
||||
#include "providers/i_provider.hpp"
|
||||
#include "utils/config.hpp"
|
||||
#include "utils/error_utils.hpp"
|
||||
#include "utils/string.hpp"
|
||||
|
||||
namespace repertory {
|
||||
auto lock_data::get_mount_state(const provider_type & /*pt*/, json &mount_state)
|
||||
-> bool {
|
||||
const auto ret = get_mount_state(mount_state);
|
||||
if (ret) {
|
||||
const auto mount_id =
|
||||
app_config::get_provider_display_name(pt_) + unique_id_;
|
||||
mount_state = mount_state[mount_id].empty()
|
||||
? json({{"Active", false}, {"Location", ""}, {"PID", -1}})
|
||||
: mount_state[mount_id];
|
||||
lock_data::lock_data(provider_type prov, std::string unique_id)
|
||||
: mutex_id_(create_lock_id(prov, unique_id)),
|
||||
mutex_handle_(::CreateMutex(nullptr, FALSE,
|
||||
create_lock_id(prov, unique_id).c_str())) {}
|
||||
|
||||
lock_data::~lock_data() { release(); }
|
||||
|
||||
auto lock_data::get_current_mount_state(json &mount_state) -> bool {
|
||||
REPERTORY_USES_FUNCTION_NAME();
|
||||
|
||||
HKEY key{};
|
||||
if (::RegOpenKeyEx(HKEY_CURRENT_USER,
|
||||
fmt::format(R"(SOFTWARE\{}\Mounts\{})",
|
||||
REPERTORY_DATA_NAME, mutex_id_)
|
||||
.c_str(),
|
||||
0, KEY_ALL_ACCESS, &key) != ERROR_SUCCESS) {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string data;
|
||||
DWORD data_size{};
|
||||
|
||||
DWORD type{REG_SZ};
|
||||
::RegGetValueA(key, nullptr, nullptr, RRF_RT_REG_SZ, &type, nullptr,
|
||||
&data_size);
|
||||
|
||||
data.resize(data_size);
|
||||
auto res = ::RegGetValueA(key, nullptr, nullptr, RRF_RT_REG_SZ, &type,
|
||||
data.data(), &data_size);
|
||||
auto ret = res == ERROR_SUCCESS || res == ERROR_FILE_NOT_FOUND;
|
||||
if (ret && data_size != 0U) {
|
||||
try {
|
||||
mount_state = json::parse(data);
|
||||
} catch (const std::exception &e) {
|
||||
utils::error::raise_error(function_name, e, "failed to read mount state");
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
|
||||
::RegCloseKey(key);
|
||||
return ret;
|
||||
}
|
||||
|
||||
auto lock_data::get_mount_state(json &mount_state) -> bool {
|
||||
HKEY key;
|
||||
auto ret = !::RegCreateKeyEx(
|
||||
HKEY_CURRENT_USER,
|
||||
("SOFTWARE\\" + std::string{REPERTORY_DATA_NAME} + "\\Mounts").c_str(), 0,
|
||||
nullptr, 0, KEY_ALL_ACCESS, nullptr, &key, nullptr);
|
||||
if (ret) {
|
||||
DWORD i = 0u;
|
||||
DWORD data_size = 0u;
|
||||
std::string name;
|
||||
name.resize(32767u);
|
||||
auto name_size = static_cast<DWORD>(name.size());
|
||||
while (ret &&
|
||||
(::RegEnumValue(key, i, &name[0], &name_size, nullptr, nullptr,
|
||||
nullptr, &data_size) == ERROR_SUCCESS)) {
|
||||
std::string data;
|
||||
data.resize(data_size);
|
||||
name_size++;
|
||||
if ((ret = !::RegEnumValue(key, i++, &name[0], &name_size, nullptr,
|
||||
nullptr, reinterpret_cast<LPBYTE>(&data[0]),
|
||||
&data_size))) {
|
||||
mount_state[name.c_str()] = json::parse(data);
|
||||
name_size = static_cast<DWORD>(name.size());
|
||||
data_size = 0u;
|
||||
}
|
||||
}
|
||||
::RegCloseKey(key);
|
||||
if (not get_current_mount_state(mount_state)) {
|
||||
return false;
|
||||
}
|
||||
return ret;
|
||||
|
||||
mount_state = mount_state.empty() ? json({
|
||||
{"Active", false},
|
||||
{"Location", ""},
|
||||
{"PID", -1},
|
||||
})
|
||||
: mount_state;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
auto lock_data::grab_lock(std::uint8_t retry_count) -> lock_result {
|
||||
REPERTORY_USES_FUNCTION_NAME();
|
||||
static constexpr const std::uint32_t max_sleep{100U};
|
||||
|
||||
auto ret = lock_result::success;
|
||||
if (mutex_handle_ == INVALID_HANDLE_VALUE) {
|
||||
ret = lock_result::failure;
|
||||
} else {
|
||||
for (auto i = 0;
|
||||
(i <= retry_count) && ((mutex_state_ = ::WaitForSingleObject(
|
||||
mutex_handle_, 100)) == WAIT_TIMEOUT);
|
||||
i++) {
|
||||
}
|
||||
|
||||
switch (mutex_state_) {
|
||||
case WAIT_OBJECT_0: {
|
||||
ret = lock_result::success;
|
||||
auto should_reset = true;
|
||||
json mount_state;
|
||||
if (get_mount_state(pt_, mount_state)) {
|
||||
if (mount_state["Active"].get<bool>() &&
|
||||
mount_state["Location"] == "elevating") {
|
||||
should_reset = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (should_reset) {
|
||||
if (not set_mount_state(false, "", -1)) {
|
||||
utils::error::raise_error(function_name, "failed to set mount state");
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case WAIT_TIMEOUT:
|
||||
ret = lock_result::locked;
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = lock_result::failure;
|
||||
break;
|
||||
}
|
||||
return lock_result::failure;
|
||||
}
|
||||
|
||||
return ret;
|
||||
for (std::uint8_t idx = 0U;
|
||||
(idx <= retry_count) &&
|
||||
((mutex_state_ = ::WaitForSingleObject(mutex_handle_, max_sleep)) ==
|
||||
WAIT_TIMEOUT);
|
||||
++idx) {
|
||||
}
|
||||
|
||||
switch (mutex_state_) {
|
||||
case WAIT_OBJECT_0:
|
||||
return lock_result::success;
|
||||
|
||||
case WAIT_TIMEOUT:
|
||||
return lock_result::locked;
|
||||
|
||||
default:
|
||||
return lock_result::failure;
|
||||
}
|
||||
}
|
||||
|
||||
void lock_data::release() {
|
||||
if (mutex_handle_ != INVALID_HANDLE_VALUE) {
|
||||
if ((mutex_state_ == WAIT_OBJECT_0) || (mutex_state_ == WAIT_ABANDONED)) {
|
||||
::ReleaseMutex(mutex_handle_);
|
||||
}
|
||||
::CloseHandle(mutex_handle_);
|
||||
mutex_handle_ = INVALID_HANDLE_VALUE;
|
||||
if (mutex_handle_ == INVALID_HANDLE_VALUE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((mutex_state_ == WAIT_OBJECT_0) || (mutex_state_ == WAIT_ABANDONED)) {
|
||||
if (mutex_state_ == WAIT_OBJECT_0) {
|
||||
[[maybe_unused]] auto success{set_mount_state(false, "", -1)};
|
||||
}
|
||||
|
||||
::ReleaseMutex(mutex_handle_);
|
||||
}
|
||||
|
||||
::CloseHandle(mutex_handle_);
|
||||
mutex_handle_ = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
auto lock_data::set_mount_state(bool active, const std::string &mount_location,
|
||||
const std::int64_t &pid) -> bool {
|
||||
auto ret = false;
|
||||
if (mutex_handle_ != INVALID_HANDLE_VALUE) {
|
||||
const auto mount_id =
|
||||
app_config::get_provider_display_name(pt_) + unique_id_;
|
||||
json mount_state;
|
||||
[[maybe_unused]] auto success = get_mount_state(mount_state);
|
||||
if ((mount_state.find(mount_id) == mount_state.end()) ||
|
||||
(mount_state[mount_id].find("Active") == mount_state[mount_id].end()) ||
|
||||
(mount_state[mount_id]["Active"].get<bool>() != active) ||
|
||||
(active && ((mount_state[mount_id].find("Location") ==
|
||||
mount_state[mount_id].end()) ||
|
||||
(mount_state[mount_id]["Location"].get<std::string>() !=
|
||||
mount_location)))) {
|
||||
HKEY key;
|
||||
if ((ret = !::RegCreateKeyEx(
|
||||
HKEY_CURRENT_USER,
|
||||
("SOFTWARE\\" + std::string{REPERTORY_DATA_NAME} + "\\Mounts")
|
||||
.c_str(),
|
||||
0, nullptr, 0, KEY_ALL_ACCESS, nullptr, &key, nullptr))) {
|
||||
const auto str = json({{"Active", active},
|
||||
{"Location", active ? mount_location : ""},
|
||||
{"PID", active ? pid : -1}})
|
||||
.dump(0);
|
||||
ret = !::RegSetValueEx(key, &mount_id[0], 0, REG_SZ,
|
||||
reinterpret_cast<const BYTE *>(&str[0]),
|
||||
static_cast<DWORD>(str.size()));
|
||||
::RegCloseKey(key);
|
||||
}
|
||||
} else {
|
||||
ret = true;
|
||||
}
|
||||
auto lock_data::set_mount_state(bool active, std::string_view mount_location,
|
||||
std::int64_t pid) -> bool {
|
||||
if (mutex_handle_ == INVALID_HANDLE_VALUE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
json mount_state;
|
||||
[[maybe_unused]] auto success{get_mount_state(mount_state)};
|
||||
if (not((mount_state.find("Active") == mount_state.end()) ||
|
||||
(mount_state["Active"].get<bool>() != active) ||
|
||||
(active &&
|
||||
((mount_state.find("Location") == mount_state.end()) ||
|
||||
(mount_state["Location"].get<std::string>() != mount_location))))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
HKEY key{};
|
||||
if (::RegCreateKeyExA(HKEY_CURRENT_USER,
|
||||
fmt::format(R"(SOFTWARE\{}\Mounts\{})",
|
||||
REPERTORY_DATA_NAME, mutex_id_)
|
||||
.c_str(),
|
||||
0, nullptr, 0, KEY_ALL_ACCESS, nullptr, &key,
|
||||
nullptr) != ERROR_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto ret{false};
|
||||
if (mount_location.empty() && not active) {
|
||||
::RegCloseKey(key);
|
||||
|
||||
if (::RegCreateKeyExA(
|
||||
HKEY_CURRENT_USER,
|
||||
fmt::format(R"(SOFTWARE\{}\Mounts)", REPERTORY_DATA_NAME).c_str(),
|
||||
0, nullptr, 0, KEY_ALL_ACCESS, nullptr, &key,
|
||||
nullptr) != ERROR_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = (::RegDeleteKeyA(key, mutex_id_.c_str()) == ERROR_SUCCESS);
|
||||
} else {
|
||||
auto data{
|
||||
json({
|
||||
{"Active", active},
|
||||
{"Location", active ? mount_location : ""},
|
||||
{"PID", active ? pid : -1},
|
||||
})
|
||||
.dump(),
|
||||
};
|
||||
ret = (::RegSetValueEx(key, nullptr, 0, REG_SZ,
|
||||
reinterpret_cast<const BYTE *>(data.c_str()),
|
||||
static_cast<DWORD>(data.size())) == ERROR_SUCCESS);
|
||||
}
|
||||
|
||||
::RegCloseKey(key);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -215,4 +236,4 @@ auto provider_meta_handler(i_provider &provider, bool directory,
|
||||
}
|
||||
} // namespace repertory
|
||||
|
||||
#endif //_WIN32
|
||||
#endif // defined(_WIN32)
|
||||
|
@@ -22,8 +22,6 @@
|
||||
#include "rpc/client/client.hpp"
|
||||
|
||||
#include "types/repertory.hpp"
|
||||
#include "utils/base64.hpp"
|
||||
#include "utils/utils.hpp"
|
||||
|
||||
namespace repertory {
|
||||
client::client(rpc_host_info host_info) : host_info_(std::move(host_info)) {}
|
||||
|
@@ -28,64 +28,16 @@
|
||||
#include "events/types/service_stop_begin.hpp"
|
||||
#include "events/types/service_stop_end.hpp"
|
||||
#include "events/types/unmount_requested.hpp"
|
||||
#include "utils/base64.hpp"
|
||||
#include "rpc/common.hpp"
|
||||
#include "utils/error_utils.hpp"
|
||||
#include "utils/string.hpp"
|
||||
|
||||
namespace repertory {
|
||||
server::server(app_config &config) : config_(config) {}
|
||||
|
||||
auto server::check_authorization(const httplib::Request &req) -> bool {
|
||||
REPERTORY_USES_FUNCTION_NAME();
|
||||
|
||||
if (config_.get_api_auth().empty() || config_.get_api_user().empty()) {
|
||||
utils::error::raise_error(function_name,
|
||||
"authorization user or password is not set");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto authorization = req.get_header_value("Authorization");
|
||||
if (authorization.empty()) {
|
||||
utils::error::raise_error(function_name, "Authorization header is not set");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto auth_parts = utils::string::split(authorization, ' ', true);
|
||||
if (auth_parts.empty()) {
|
||||
utils::error::raise_error(function_name, "Authorization header is empty");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto auth_type = auth_parts[0U];
|
||||
if (auth_type != "Basic") {
|
||||
utils::error::raise_error(function_name, "Authorization is not Basic");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto data = macaron::Base64::Decode(authorization.substr(6U));
|
||||
auto auth_str = std::string(data.begin(), data.end());
|
||||
|
||||
auto auth = utils::string::split(auth_str, ':', false);
|
||||
if (auth.size() < 2U) {
|
||||
utils::error::raise_error(function_name, "Authorization is not valid");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto user = auth.at(0U);
|
||||
auth.erase(auth.begin());
|
||||
|
||||
auto pwd = utils::string::join(auth, ':');
|
||||
if ((user != config_.get_api_user()) || (pwd != config_.get_api_auth())) {
|
||||
utils::error::raise_error(function_name, "Authorization failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void server::handle_get_config(const httplib::Request & /*req*/,
|
||||
httplib::Response &res) {
|
||||
auto data = config_.get_json();
|
||||
clean_json_config(config_.get_provider_type(), data);
|
||||
res.set_content(data.dump(), "application/json");
|
||||
res.status = http_error_codes::ok;
|
||||
}
|
||||
@@ -93,7 +45,10 @@ void server::handle_get_config(const httplib::Request & /*req*/,
|
||||
void server::handle_get_config_value_by_name(const httplib::Request &req,
|
||||
httplib::Response &res) {
|
||||
auto name = req.get_param_value("name");
|
||||
auto data = json({{"value", config_.get_value_by_name(name)}});
|
||||
auto data = json({{
|
||||
"value",
|
||||
clean_json_value(name, config_.get_value_by_name(name)),
|
||||
}});
|
||||
res.set_content(data.dump(), "application/json");
|
||||
res.status = http_error_codes::ok;
|
||||
}
|
||||
@@ -103,7 +58,10 @@ void server::handle_set_config_value_by_name(const httplib::Request &req,
|
||||
auto name = req.get_param_value("name");
|
||||
auto value = req.get_param_value("value");
|
||||
|
||||
json data = {{"value", config_.set_value_by_name(name, value)}};
|
||||
json data = {{
|
||||
"value",
|
||||
clean_json_value(name, config_.set_value_by_name(name, value)),
|
||||
}};
|
||||
res.set_content(data.dump(), "application/json");
|
||||
res.status = http_error_codes::ok;
|
||||
}
|
||||
@@ -173,7 +131,7 @@ void server::start() {
|
||||
|
||||
server_->set_pre_routing_handler(
|
||||
[this](auto &&req, auto &&res) -> httplib::Server::HandlerResponse {
|
||||
if (check_authorization(req)) {
|
||||
if (rpc::check_authorization(config_, req)) {
|
||||
return httplib::Server::HandlerResponse::Unhandled;
|
||||
}
|
||||
|
||||
@@ -183,8 +141,21 @@ void server::start() {
|
||||
|
||||
initialize(*server_);
|
||||
|
||||
server_thread_ = std::make_unique<std::thread>(
|
||||
[this]() { server_->listen("127.0.0.1", config_.get_api_port()); });
|
||||
server_thread_ = std::make_unique<std::thread>([this]() {
|
||||
server_->set_socket_options([](auto &&sock) {
|
||||
#if defined(_WIN32)
|
||||
int enable{1};
|
||||
setsockopt(sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
|
||||
reinterpret_cast<const char *>(&enable), sizeof(enable));
|
||||
#else // !defined(_WIN32)
|
||||
linger opt{1, 0};
|
||||
setsockopt(sock, SOL_SOCKET, SO_LINGER,
|
||||
reinterpret_cast<const char *>(&opt), sizeof(opt));
|
||||
#endif // defined(_WIN32)
|
||||
});
|
||||
|
||||
server_->listen("127.0.0.1", config_.get_api_port());
|
||||
});
|
||||
event_system::instance().raise<service_start_end>(function_name, "server");
|
||||
}
|
||||
|
||||
|
@@ -21,10 +21,56 @@
|
||||
*/
|
||||
#include "types/repertory.hpp"
|
||||
|
||||
#include "app_config.hpp"
|
||||
#include "types/startup_exception.hpp"
|
||||
#include "utils/string.hpp"
|
||||
|
||||
namespace repertory {
|
||||
void clean_json_config(provider_type prov, nlohmann::json &data) {
|
||||
data[JSON_API_PASSWORD] = "";
|
||||
|
||||
switch (prov) {
|
||||
case provider_type::encrypt:
|
||||
data[JSON_ENCRYPT_CONFIG][JSON_ENCRYPTION_TOKEN] = "";
|
||||
data[JSON_REMOTE_MOUNT][JSON_ENCRYPTION_TOKEN] = "";
|
||||
break;
|
||||
|
||||
case provider_type::remote:
|
||||
data[JSON_REMOTE_CONFIG][JSON_ENCRYPTION_TOKEN] = "";
|
||||
break;
|
||||
|
||||
case provider_type::s3:
|
||||
data[JSON_REMOTE_MOUNT][JSON_ENCRYPTION_TOKEN] = "";
|
||||
data[JSON_S3_CONFIG][JSON_ENCRYPTION_TOKEN] = "";
|
||||
data[JSON_S3_CONFIG][JSON_SECRET_KEY] = "";
|
||||
break;
|
||||
|
||||
case provider_type::sia:
|
||||
data[JSON_REMOTE_MOUNT][JSON_ENCRYPTION_TOKEN] = "";
|
||||
data[JSON_HOST_CONFIG][JSON_API_PASSWORD] = "";
|
||||
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
auto clean_json_value(std::string_view name, std::string_view data)
|
||||
-> std::string {
|
||||
if (name ==
|
||||
fmt::format("{}.{}", JSON_ENCRYPT_CONFIG, JSON_ENCRYPTION_TOKEN) ||
|
||||
name == fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_API_PASSWORD) ||
|
||||
name == fmt::format("{}.{}", JSON_REMOTE_CONFIG, JSON_ENCRYPTION_TOKEN) ||
|
||||
name == fmt::format("{}.{}", JSON_REMOTE_MOUNT, JSON_ENCRYPTION_TOKEN) ||
|
||||
name == fmt::format("{}.{}", JSON_S3_CONFIG, JSON_ENCRYPTION_TOKEN) ||
|
||||
name == fmt::format("{}.{}", JSON_S3_CONFIG, JSON_SECRET_KEY) ||
|
||||
name == JSON_API_PASSWORD) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return std::string{data};
|
||||
}
|
||||
|
||||
auto database_type_from_string(std::string type, database_type default_type)
|
||||
-> database_type {
|
||||
type = utils::string::to_lower(utils::string::trim(type));
|
||||
@@ -191,4 +237,34 @@ auto api_error_to_string(const api_error &error) -> const std::string & {
|
||||
|
||||
return LOOKUP.at(error);
|
||||
}
|
||||
|
||||
auto provider_type_from_string(std::string_view type,
|
||||
provider_type default_type) -> provider_type {
|
||||
auto type_lower = utils::string::to_lower(std::string{type});
|
||||
if (type_lower == "encrypt") {
|
||||
return provider_type::encrypt;
|
||||
}
|
||||
|
||||
if (type_lower == "remote") {
|
||||
return provider_type::remote;
|
||||
}
|
||||
|
||||
if (type_lower == "s3") {
|
||||
return provider_type::s3;
|
||||
}
|
||||
|
||||
if (type_lower == "sia") {
|
||||
return provider_type::sia;
|
||||
}
|
||||
|
||||
if (type_lower == "unknown") {
|
||||
return provider_type::unknown;
|
||||
}
|
||||
|
||||
return default_type;
|
||||
}
|
||||
|
||||
auto provider_type_to_string(provider_type type) -> std::string {
|
||||
return app_config::get_provider_name(type);
|
||||
}
|
||||
} // namespace repertory
|
||||
|
@@ -45,7 +45,7 @@ void get_api_authentication_data(std::string &user, std::string &password,
|
||||
|
||||
if (success) {
|
||||
if (user.empty() && password.empty()) {
|
||||
password = data[JSON_API_AUTH].get<std::string>();
|
||||
password = data[JSON_API_PASSWORD].get<std::string>();
|
||||
user = data[JSON_API_USER].get<std::string>();
|
||||
}
|
||||
port = data[JSON_API_PORT].get<std::uint16_t>();
|
||||
|
@@ -44,11 +44,13 @@ struct repertory_exception_handler final
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<repertory_exception_handler> handler{([]() -> auto * {
|
||||
auto *ptr = new repertory_exception_handler{};
|
||||
repertory::utils::error::set_exception_handler(ptr);
|
||||
return ptr;
|
||||
})()};
|
||||
const auto repertory_handler{
|
||||
([]() -> auto {
|
||||
auto ptr = std::make_unique<repertory_exception_handler>();
|
||||
repertory::utils::error::set_exception_handler(ptr.get());
|
||||
return ptr;
|
||||
})(),
|
||||
};
|
||||
} // namespace
|
||||
|
||||
namespace repertory::utils::error {
|
||||
|
31
repertory/librepertory/src/utils/platform.cpp
Normal file
31
repertory/librepertory/src/utils/platform.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
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 "platform/platform.hpp"
|
||||
|
||||
#include "app_config.hpp"
|
||||
|
||||
namespace repertory {
|
||||
auto create_lock_id(provider_type prov, std::string_view unique_id)->std::string {
|
||||
return fmt::format("{}_{}_{}", REPERTORY_DATA_NAME,
|
||||
app_config::get_provider_name(prov), unique_id);
|
||||
}
|
||||
} // namespace repertory
|
Reference in New Issue
Block a user