Merge branch 'v2.1.0-rc-develop' of https://git.fifthgrid.com/blockstorage/repertory into v2.1.0-rc-develop
This commit is contained in:
@@ -134,6 +134,19 @@ unmount_existing_repertory_volumes() {
|
||||
# ----- user LaunchAgents (by LABEL_PREFIX only) -----
|
||||
get_plist_label() { /usr/bin/defaults read "$1" Label 2>/dev/null || /usr/libexec/PlistBuddy -c "Print :Label" "$1" 2>/dev/null || basename "$1" .plist; }
|
||||
|
||||
# Return the executable path a LaunchAgent runs (ProgramArguments[0] or Program).
|
||||
# Echoes empty string if neither is present.
|
||||
get_plist_exec_path() {
|
||||
local plist="$1" arg0=""
|
||||
# Prefer ProgramArguments[0]
|
||||
arg0="$(/usr/libexec/PlistBuddy -c 'Print :ProgramArguments:0' "$plist" 2>/dev/null || true)"
|
||||
if [[ -z "$arg0" ]]; then
|
||||
# Fallback to Program (older style)
|
||||
arg0="$(/usr/libexec/PlistBuddy -c 'Print :Program' "$plist" 2>/dev/null || true)"
|
||||
fi
|
||||
printf '%s\n' "$arg0"
|
||||
}
|
||||
|
||||
snapshot_launchagents_user() {
|
||||
local user_agents="$HOME/Library/LaunchAgents"
|
||||
snapfile="$(/usr/bin/mktemp "/tmp/repertory_launchagents.XXXXXX")" || snapfile=""
|
||||
@@ -141,16 +154,48 @@ snapshot_launchagents_user() {
|
||||
warn "Could not create temporary snapshot file; skipping LaunchAgent restart snapshot."
|
||||
return 0
|
||||
fi
|
||||
if [[ -d "$user_agents" ]]; then
|
||||
[[ -d "$user_agents" ]] || return 0
|
||||
|
||||
# We collect non-UI first, then UI last, to preserve restart order later.
|
||||
local tmp_nonui tmp_ui
|
||||
tmp_nonui="$(/usr/bin/mktemp "/tmp/repertory_launchagents.nonui.XXXXXX")" || tmp_nonui=""
|
||||
tmp_ui="$(/usr/bin/mktemp "/tmp/repertory_launchagents.ui.XXXXXX")" || tmp_ui=""
|
||||
|
||||
/usr/bin/find "$user_agents" -maxdepth 1 -type f -name "${LABEL_PREFIX}"'*.plist' -print 2>/dev/null |
|
||||
while IFS= read -r plist; do
|
||||
[[ -z "$plist" ]] && continue
|
||||
|
||||
# Label must match the prefix
|
||||
local label
|
||||
label="$(get_plist_label "$plist")"
|
||||
[[ -n "$label" && "$label" == "${LABEL_PREFIX}"* ]] || continue
|
||||
printf "%s\t%s\n" "$plist" "$label" >>"$snapfile"
|
||||
done
|
||||
|
||||
# Executable must point into the *installed* app path
|
||||
local exec_path
|
||||
exec_path="$(get_plist_exec_path "$plist")"
|
||||
[[ -n "$exec_path" ]] || continue
|
||||
# Normalize: only accept absolute paths under $dest_app (e.g. .../repertory.app/Contents/...)
|
||||
if [[ "$exec_path" != "$dest_app/"* ]]; then
|
||||
# Not one of ours; skip
|
||||
continue
|
||||
fi
|
||||
|
||||
# Defer UI label to the end
|
||||
if [[ "$label" == "$UI_LABEL" ]]; then
|
||||
[[ -n "$tmp_ui" ]] && printf "%s\t%s\n" "$plist" "$label" >>"$tmp_ui"
|
||||
else
|
||||
[[ -n "$tmp_nonui" ]] && printf "%s\t%s\n" "$plist" "$label" >>"$tmp_nonui"
|
||||
fi
|
||||
done
|
||||
|
||||
# Stitch together: non-UI first, then UI
|
||||
[[ -s "$tmp_nonui" ]] && /bin/cat "$tmp_nonui" >>"$snapfile"
|
||||
[[ -s "$tmp_ui" ]] && /bin/cat "$tmp_ui" >>"$snapfile"
|
||||
|
||||
[[ -n "$tmp_nonui" ]] && /bin/rm -f "$tmp_nonui" 2>/dev/null || true
|
||||
[[ -n "$tmp_ui" ]] && /bin/rm -f "$tmp_ui" 2>/dev/null || true
|
||||
|
||||
log "Snapshot contains $(/usr/bin/wc -l <"$snapfile" 2>/dev/null || echo 0) LaunchAgent(s)."
|
||||
}
|
||||
|
||||
unload_launchd_helpers_user() {
|
||||
|
@@ -447,7 +447,7 @@ auto fuse_base::mount([[maybe_unused]] std::vector<std::string> orig_args,
|
||||
return -1;
|
||||
}
|
||||
|
||||
orig_args[0U] = utils::path::combine(".", {"repertory"});
|
||||
orig_args[0U] = utils::path::combine(".", {REPERTORY});
|
||||
orig_args.insert(std::next(orig_args.begin()), "-f");
|
||||
|
||||
utils::plist_cfg cfg{};
|
||||
|
@@ -36,10 +36,11 @@ private:
|
||||
|
||||
private:
|
||||
std::atomic<bool> animations_{true};
|
||||
utils::atomic<std::string> api_password_{"repertory"};
|
||||
utils::atomic<std::string> api_password_{std::string{REPERTORY}};
|
||||
std::atomic<std::uint16_t> api_port_{default_ui_mgmt_port};
|
||||
utils::atomic<std::string> api_user_{"repertory"};
|
||||
utils::atomic<std::string> api_user_{std::string{REPERTORY}};
|
||||
std::atomic<bool> auto_start_{true};
|
||||
std::atomic<event_level> event_level_{event_level::info};
|
||||
std::unordered_map<provider_type,
|
||||
std::unordered_map<std::string, std::string>>
|
||||
locations_;
|
||||
@@ -71,6 +72,10 @@ public:
|
||||
[[nodiscard]] auto get_auto_start_list() const
|
||||
-> std::unordered_map<provider_type, std::vector<std::string>>;
|
||||
|
||||
[[nodiscard]] auto get_event_level() const -> event_level {
|
||||
return event_level_;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_hidden() const -> bool { return hidden_; }
|
||||
|
||||
[[nodiscard]] auto get_launch_only() const -> bool { return launch_only_; }
|
||||
@@ -92,6 +97,8 @@ public:
|
||||
void set_auto_start(provider_type prov, std::string_view name,
|
||||
bool auto_start);
|
||||
|
||||
void set_event_level(event_level level);
|
||||
|
||||
void set_hidden(bool hidden);
|
||||
|
||||
void set_launch_only(bool launch_only);
|
||||
|
@@ -19,16 +19,17 @@
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
#ifndef REPERTORY_INCLUDE_UI_HANDLERS_HPP_
|
||||
#define REPERTORY_INCLUDE_UI_HANDLERS_HPP_
|
||||
#ifndef REPERTORY_INCLUDE_UI_SERVER_HPP_
|
||||
#define REPERTORY_INCLUDE_UI_SERVER_HPP_
|
||||
|
||||
#include "events/consumers/console_consumer.hpp"
|
||||
#include "events/consumers/logging_consumer.hpp"
|
||||
#include "utils/common.hpp"
|
||||
|
||||
namespace repertory::ui {
|
||||
class mgmt_app_config;
|
||||
|
||||
class handlers final {
|
||||
class ui_server final {
|
||||
private:
|
||||
static constexpr auto nonce_length{128U};
|
||||
static constexpr auto nonce_timeout{15U};
|
||||
@@ -44,21 +45,21 @@ private:
|
||||
};
|
||||
|
||||
public:
|
||||
handlers(mgmt_app_config *config, httplib::Server *server);
|
||||
ui_server(mgmt_app_config *config);
|
||||
|
||||
handlers() = delete;
|
||||
handlers(const handlers &) = delete;
|
||||
handlers(handlers &&) = delete;
|
||||
ui_server() = delete;
|
||||
ui_server(const ui_server &) = delete;
|
||||
ui_server(ui_server &&) = delete;
|
||||
|
||||
~handlers();
|
||||
~ui_server();
|
||||
|
||||
auto operator=(const handlers &) -> handlers & = delete;
|
||||
auto operator=(handlers &&) -> handlers & = delete;
|
||||
auto operator=(const ui_server &) -> ui_server & = delete;
|
||||
auto operator=(ui_server &&) -> ui_server & = delete;
|
||||
|
||||
private:
|
||||
mgmt_app_config *config_;
|
||||
logging_consumer logging;
|
||||
std::string repertory_binary_;
|
||||
httplib::Server *server_;
|
||||
|
||||
private:
|
||||
console_consumer console;
|
||||
@@ -68,6 +69,7 @@ private:
|
||||
std::unordered_map<std::string, nonce_data> nonce_lookup_;
|
||||
std::condition_variable nonce_notify_;
|
||||
std::unique_ptr<std::thread> nonce_thread_;
|
||||
httplib::Server server_;
|
||||
stop_type stop_requested{false};
|
||||
mutable std::mutex test_mtx_;
|
||||
|
||||
@@ -127,12 +129,19 @@ private:
|
||||
[[nodiscard]] auto mount(provider_type prov, std::string_view name,
|
||||
const std::string &location) -> bool;
|
||||
|
||||
void notify_and_unlock(unique_mutex_lock &nonce_lock);
|
||||
|
||||
void removed_expired_nonces();
|
||||
|
||||
void set_key_value(provider_type prov, std::string_view name,
|
||||
std::string_view key, std::string_view value,
|
||||
std::optional<std::string> data_dir = std::nullopt) const;
|
||||
|
||||
public:
|
||||
void start();
|
||||
|
||||
void stop();
|
||||
};
|
||||
} // namespace repertory::ui
|
||||
|
||||
#endif // REPERTORY_INCLUDE_UI_HANDLERS_HPP_
|
||||
#endif // REPERTORY_INCLUDE_UI_SERVER_HPP_
|
@@ -26,9 +26,10 @@
|
||||
#include "cli/actions.hpp"
|
||||
#include "initialize.hpp"
|
||||
#include "types/repertory.hpp"
|
||||
#include "ui/handlers.hpp"
|
||||
#include "ui/mgmt_app_config.hpp"
|
||||
#include "ui/ui_server.hpp"
|
||||
#include "utils/cli_utils.hpp"
|
||||
#include "utils/error_utils.hpp"
|
||||
#include "utils/polling.hpp"
|
||||
|
||||
using namespace repertory;
|
||||
@@ -80,18 +81,51 @@ auto main(int argc, char **argv) -> int {
|
||||
if (not utils::file::change_to_process_directory()) {
|
||||
ret = static_cast<std::int32_t>(exit_code::ui_failed);
|
||||
} else {
|
||||
httplib::Server server;
|
||||
#if defined(__APPLE__)
|
||||
if (not server.set_mount_point("/ui", "../Resources/web")) {
|
||||
#else // !defined(__APPLE__)
|
||||
if (not server.set_mount_point("/ui", "./web")) {
|
||||
#endif // defined(__APPLE__)
|
||||
ret = static_cast<std::int32_t>(exit_code::ui_failed);
|
||||
} else {
|
||||
const auto run_ui = [](auto *server) {
|
||||
REPERTORY_USES_FUNCTION_NAME();
|
||||
|
||||
static std::atomic<ui::ui_server *> active_server{server};
|
||||
static const auto quit_handler = [](int /* sig */) {
|
||||
REPERTORY_USES_FUNCTION_NAME();
|
||||
|
||||
auto *ptr = active_server.exchange(nullptr);
|
||||
if (ptr == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
ptr->stop();
|
||||
} catch (const std::exception &ex) {
|
||||
utils::error::raise_error(function_name, ex, "failed to stop ui");
|
||||
}
|
||||
};
|
||||
|
||||
std::signal(SIGINT, quit_handler);
|
||||
#if !defined(_WIN32)
|
||||
std::signal(SIGQUIT, quit_handler);
|
||||
#endif // !defined(_WIN32)
|
||||
std::signal(SIGTERM, quit_handler);
|
||||
|
||||
try {
|
||||
server->start();
|
||||
} catch (const std::exception &ex) {
|
||||
utils::error::raise_error(function_name, ex, "failed to start ui");
|
||||
}
|
||||
|
||||
try {
|
||||
server->stop();
|
||||
} catch (const std::exception &ex) {
|
||||
utils::error::raise_error(function_name, ex, "failed to stop ui");
|
||||
}
|
||||
|
||||
repertory::project_cleanup();
|
||||
};
|
||||
|
||||
#if defined(_WIN32)
|
||||
ui::handlers handlers(&config, &server);
|
||||
ui::server server(&config);
|
||||
run_ui(&server);
|
||||
#else // !defined(_WIN32)
|
||||
project_cleanup();
|
||||
repertory::project_cleanup();
|
||||
|
||||
ret = utils::create_daemon([&]() -> int {
|
||||
if (not repertory::project_initialize()) {
|
||||
@@ -103,13 +137,12 @@ auto main(int argc, char **argv) -> int {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ui::handlers handlers(&config, &server);
|
||||
project_cleanup();
|
||||
ui::ui_server server(&config);
|
||||
run_ui(&server);
|
||||
return 0;
|
||||
});
|
||||
#endif // defined(_WIN32)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
auto prov = utils::cli::get_provider_type_from_args(args);
|
||||
|
||||
|
@@ -112,6 +112,13 @@ mgmt_app_config::mgmt_app_config(bool hidden, bool launch_only)
|
||||
should_save = true;
|
||||
}
|
||||
|
||||
if (data.contains(JSON_EVENT_LEVEL)) {
|
||||
event_level_ = event_level_from_string(
|
||||
data.at(JSON_EVENT_LEVEL).get<std::string>());
|
||||
} else {
|
||||
should_save = true;
|
||||
}
|
||||
|
||||
if (data.contains(JSON_MOUNT_LOCATIONS)) {
|
||||
locations_ = from_json<std::string>(data.at(JSON_MOUNT_LOCATIONS));
|
||||
} else {
|
||||
@@ -249,11 +256,12 @@ void mgmt_app_config::set_auto_start(bool auto_start) {
|
||||
#if defined(__linux__)
|
||||
if (auto_start) {
|
||||
utils::autostart_cfg cfg{};
|
||||
cfg.app_name = "repertory";
|
||||
cfg.app_name = REPERTORY;
|
||||
cfg.comment = "Mount utility for AWS S3 and Sia";
|
||||
cfg.exec_args = {"-ui", "-lo"};
|
||||
cfg.exec_path = utils::path::combine(".", {"repertory"});
|
||||
cfg.icon_path = utils::path::combine(".", {"repertory.png"});
|
||||
cfg.exec_path = utils::path::combine(".", {REPERTORY});
|
||||
cfg.icon_path =
|
||||
utils::path::combine(".", {std::string{REPERTORY} + ".png"});
|
||||
cfg.terminal = true;
|
||||
|
||||
if (utils::create_autostart_entry(cfg, false)) {
|
||||
@@ -264,7 +272,7 @@ void mgmt_app_config::set_auto_start(bool auto_start) {
|
||||
function_name, utils::get_last_error_code(),
|
||||
"failed to create auto-start entry|name|repertory");
|
||||
}
|
||||
} else if (utils::remove_autostart_entry("repertory")) {
|
||||
} else if (utils::remove_autostart_entry(REPERTORY)) {
|
||||
utils::error::handle_info(function_name,
|
||||
"removed auto-start entry|name|repertory");
|
||||
} else {
|
||||
@@ -278,9 +286,9 @@ void mgmt_app_config::set_auto_start(bool auto_start) {
|
||||
if (auto_start) {
|
||||
utils::shortcut_cfg cfg{};
|
||||
cfg.arguments = L"-ui -lo --hidden";
|
||||
cfg.exe_path = utils::path::combine(L".", {L"repertory"});
|
||||
cfg.exe_path = utils::path::combine(L".", {REPERTORY_W});
|
||||
cfg.icon_path = utils::path::combine(L".", {L"icon.ico"});
|
||||
cfg.shortcut_name = L"repertory";
|
||||
cfg.shortcut_name = REPERTORY_W;
|
||||
cfg.working_directory = utils::path::absolute(L".");
|
||||
|
||||
if (utils::create_shortcut(cfg, false)) {
|
||||
@@ -291,7 +299,7 @@ void mgmt_app_config::set_auto_start(bool auto_start) {
|
||||
function_name, utils::get_last_error_code(),
|
||||
"failed to create auto-start entry|name|repertory");
|
||||
}
|
||||
} else if (utils::remove_shortcut(L"repertory")) {
|
||||
} else if (utils::remove_shortcut(REPERTORY_W)) {
|
||||
utils::error::handle_info(function_name,
|
||||
"removed auto-start entry|name|repertory");
|
||||
} else {
|
||||
@@ -307,7 +315,7 @@ void mgmt_app_config::set_auto_start(bool auto_start) {
|
||||
if (auto_start) {
|
||||
utils::plist_cfg cfg{};
|
||||
cfg.args = {
|
||||
utils::path::combine(".", {"repertory"}),
|
||||
utils::path::combine(".", {REPERTORY}),
|
||||
"-ui",
|
||||
"-lo",
|
||||
};
|
||||
@@ -365,6 +373,10 @@ void mgmt_app_config::set_auto_start(provider_type prov, std::string_view name,
|
||||
save();
|
||||
}
|
||||
|
||||
void mgmt_app_config::set_event_level(event_level level) {
|
||||
event_level_ = level;
|
||||
}
|
||||
|
||||
void mgmt_app_config::set_hidden(bool hidden) { hidden_ = hidden; }
|
||||
|
||||
void mgmt_app_config::set_launch_only(bool launch_only) {
|
||||
@@ -395,6 +407,7 @@ auto mgmt_app_config::to_json() const -> nlohmann::json {
|
||||
data[JSON_API_PORT] = api_port_;
|
||||
data[JSON_API_USER] = api_user_;
|
||||
data[JSON_AUTO_START] = auto_start_;
|
||||
data[JSON_EVENT_LEVEL] = event_level_to_string(event_level_);
|
||||
data[JSON_MOUNT_AUTO_START] = map_to_json(mount_auto_start_);
|
||||
data[JSON_MOUNT_LOCATIONS] = map_to_json(locations_);
|
||||
return data;
|
||||
|
@@ -19,9 +19,11 @@
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "ui/handlers.hpp"
|
||||
#include "ui/ui_server.hpp"
|
||||
|
||||
#include "app_config.hpp"
|
||||
#include "events/consumers/console_consumer.hpp"
|
||||
#include "events/consumers/logging_consumer.hpp"
|
||||
#include "events/event_system.hpp"
|
||||
#include "platform/platform.hpp"
|
||||
#include "types/repertory.hpp"
|
||||
@@ -109,54 +111,30 @@ namespace {
|
||||
return errno;
|
||||
#endif // defined(_WIN32)
|
||||
}
|
||||
|
||||
[[nodiscard]] auto is_addr_in_use(int err) -> bool {
|
||||
#if defined(_WIN32)
|
||||
return err == WSAEADDRINUSE;
|
||||
#else // !defined(_WIN32)
|
||||
return err == EADDRINUSE;
|
||||
#endif // defined(_WIN32)
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace repertory::ui {
|
||||
handlers::handlers(mgmt_app_config *config, httplib::Server *server)
|
||||
ui_server::ui_server(mgmt_app_config *config)
|
||||
: config_(config),
|
||||
logging(config->get_event_level(),
|
||||
utils::path::combine(app_config::get_root_data_directory(),
|
||||
{
|
||||
"ui",
|
||||
"logs",
|
||||
})),
|
||||
#if defined(_WIN32)
|
||||
repertory_binary_(utils::path::combine(".", {"repertory.exe"})),
|
||||
repertory_binary_(utils::path::combine(".", {REPERTORY ".exe"}))
|
||||
#else // !defined(_WIN32)
|
||||
repertory_binary_(utils::path::combine(".", {"repertory"})),
|
||||
repertory_binary_(utils::path::combine(".", {REPERTORY}))
|
||||
#endif // defined(_WIN32)
|
||||
server_(server) {
|
||||
REPERTORY_USES_FUNCTION_NAME();
|
||||
{
|
||||
#if defined(__APPLE__)
|
||||
server_.set_mount_point("/ui", "../Resources/web");
|
||||
#else // !defined(__APPLE__)
|
||||
server_.set_mount_point("/ui", "./web");
|
||||
#endif // defined(__APPLE__)
|
||||
|
||||
#if defined(_WIN32)
|
||||
if (config_->get_hidden()) {
|
||||
::ShowWindow(::GetConsoleWindow(), SW_HIDE);
|
||||
}
|
||||
#endif // defined(_WIN32)
|
||||
|
||||
if (not config_->get_launch_only()) {
|
||||
#if defined(_WIN32)
|
||||
system(
|
||||
fmt::format(
|
||||
R"(start "Repertory Management Portal" "http://127.0.0.1:{}/ui")",
|
||||
config_->get_api_port())
|
||||
.c_str());
|
||||
#elif defined(__linux__)
|
||||
system(fmt::format(R"(xdg-open "http://127.0.0.1:{}/ui")",
|
||||
config_->get_api_port())
|
||||
.c_str());
|
||||
#elif defined(__APPLE__)
|
||||
system(
|
||||
fmt::format(R"(open "http://127.0.0.1:{}/ui")", config_->get_api_port())
|
||||
.c_str());
|
||||
#else
|
||||
build fails here
|
||||
#endif
|
||||
}
|
||||
|
||||
server_->set_socket_options([](auto &&sock) {
|
||||
server_.set_socket_options([](auto &&sock) {
|
||||
#if defined(_WIN32)
|
||||
BOOL enable = TRUE;
|
||||
::setsockopt(sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
|
||||
@@ -176,7 +154,7 @@ handlers::handlers(mgmt_app_config *config, httplib::Server *server)
|
||||
#endif
|
||||
});
|
||||
|
||||
server_->set_pre_routing_handler(
|
||||
server_.set_pre_routing_handler(
|
||||
[this](const httplib::Request &req,
|
||||
auto &&res) -> httplib::Server::HandlerResponse {
|
||||
if (req.path == "/api/v1/nonce" || req.path == "/ui" ||
|
||||
@@ -190,7 +168,7 @@ handlers::handlers(mgmt_app_config *config, httplib::Server *server)
|
||||
auth, fmt::format("{}_", config_->get_api_user()))) {
|
||||
auto nonce = auth.substr(config_->get_api_user().length() + 1U);
|
||||
|
||||
mutex_lock lock(nonce_mtx_);
|
||||
mutex_lock nonce_lock(nonce_mtx_);
|
||||
if (nonce_lookup_.contains(nonce)) {
|
||||
nonce_lookup_.erase(nonce);
|
||||
return httplib::Server::HandlerResponse::Unhandled;
|
||||
@@ -201,9 +179,11 @@ handlers::handlers(mgmt_app_config *config, httplib::Server *server)
|
||||
return httplib::Server::HandlerResponse::Handled;
|
||||
});
|
||||
|
||||
server_->set_exception_handler([](const httplib::Request &req,
|
||||
server_.set_exception_handler([](const httplib::Request &req,
|
||||
httplib::Response &res,
|
||||
std::exception_ptr ptr) {
|
||||
REPERTORY_USES_FUNCTION_NAME();
|
||||
|
||||
json data{
|
||||
{"path", req.path},
|
||||
};
|
||||
@@ -227,196 +207,71 @@ handlers::handlers(mgmt_app_config *config, httplib::Server *server)
|
||||
: http_error_codes::internal_error;
|
||||
});
|
||||
|
||||
server->Get("/api/v1/locations", [](auto && /* req */, auto &&res) {
|
||||
server_.Get("/api/v1/locations", [](auto && /* req */, auto &&res) {
|
||||
handle_get_available_locations(res);
|
||||
});
|
||||
|
||||
server->Get("/api/v1/mount",
|
||||
server_.Get("/api/v1/mount",
|
||||
[this](auto &&req, auto &&res) { handle_get_mount(req, res); });
|
||||
|
||||
server->Get("/api/v1/mount_location", [this](auto &&req, auto &&res) {
|
||||
server_.Get("/api/v1/mount_location", [this](auto &&req, auto &&res) {
|
||||
handle_get_mount_location(req, res);
|
||||
});
|
||||
|
||||
server->Get("/api/v1/mount_list", [](auto && /* req */, auto &&res) {
|
||||
server_.Get("/api/v1/mount_list", [](auto && /* req */, auto &&res) {
|
||||
handle_get_mount_list(res);
|
||||
});
|
||||
|
||||
server->Get("/api/v1/mount_status", [this](auto &&req, auto &&res) {
|
||||
server_.Get("/api/v1/mount_status", [this](auto &&req, auto &&res) {
|
||||
handle_get_mount_status(req, res);
|
||||
});
|
||||
|
||||
server->Get("/api/v1/nonce",
|
||||
server_.Get("/api/v1/nonce",
|
||||
[this](auto && /* req */, auto &&res) { handle_get_nonce(res); });
|
||||
|
||||
server->Get("/api/v1/settings", [this](auto && /* req */, auto &&res) {
|
||||
server_.Get("/api/v1/settings", [this](auto && /* req */, auto &&res) {
|
||||
handle_get_settings(res);
|
||||
});
|
||||
|
||||
server->Get("/api/v1/test",
|
||||
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) {
|
||||
server_.Post("/api/v1/add_mount", [this](auto &&req, auto &&res) {
|
||||
handle_post_add_mount(req, res);
|
||||
});
|
||||
|
||||
server->Post("/api/v1/mount",
|
||||
server_.Post("/api/v1/mount",
|
||||
[this](auto &&req, auto &&res) { handle_post_mount(req, res); });
|
||||
|
||||
server->Put("/api/v1/mount_auto_start", [this](auto &&req, auto &&res) {
|
||||
server_.Put("/api/v1/mount_auto_start", [this](auto &&req, auto &&res) {
|
||||
handle_put_mount_auto_start(req, res);
|
||||
});
|
||||
|
||||
server->Put("/api/v1/mount_location", [this](auto &&req, auto &&res) {
|
||||
server_.Put("/api/v1/mount_location", [this](auto &&req, auto &&res) {
|
||||
handle_put_mount_location(req, res);
|
||||
});
|
||||
|
||||
server->Put("/api/v1/set_value_by_name", [this](auto &&req, auto &&res) {
|
||||
server_.Put("/api/v1/set_value_by_name", [this](auto &&req, auto &&res) {
|
||||
handle_put_set_value_by_name(req, res);
|
||||
});
|
||||
|
||||
server->Put("/api/v1/setting",
|
||||
server_.Put("/api/v1/setting",
|
||||
[this](auto &&req, auto &&res) { handle_put_setting(req, res); });
|
||||
|
||||
server->Put("/api/v1/settings", [this](auto &&req, auto &&res) {
|
||||
server_.Put("/api/v1/settings", [this](auto &&req, auto &&res) {
|
||||
handle_put_settings(req, res);
|
||||
});
|
||||
|
||||
static std::atomic<httplib::Server *> this_server{server_};
|
||||
static const auto quit_handler = [](int /* sig */) {
|
||||
auto *ptr = this_server.exchange(nullptr);
|
||||
if (ptr == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
std::jthread([ptr]() { ptr->stop(); });
|
||||
#else // !defined(_WIN32)
|
||||
ptr->stop();
|
||||
if (config_->get_hidden()) {
|
||||
::ShowWindow(::GetConsoleWindow(), SW_HIDE);
|
||||
}
|
||||
#endif // defined(_WIN32)
|
||||
};
|
||||
|
||||
std::signal(SIGINT, quit_handler);
|
||||
#if !defined(_WIN32)
|
||||
std::signal(SIGQUIT, quit_handler);
|
||||
#endif // !defined(_WIN32)
|
||||
std::signal(SIGTERM, quit_handler);
|
||||
|
||||
event_system::instance().start();
|
||||
|
||||
{
|
||||
auto deadline = std::chrono::steady_clock::now() + 30s;
|
||||
std::string host{"127.0.0.1"};
|
||||
auto desired_port = config_->get_api_port();
|
||||
for (;;) {
|
||||
if (server_->bind_to_port(host, desired_port)) {
|
||||
break; // bound successfully; proceed to route registration
|
||||
}
|
||||
|
||||
const auto err = get_last_net_error();
|
||||
if (!is_addr_in_use(err)) {
|
||||
utils::error::raise_error(function_name,
|
||||
utils::error::create_error_message({
|
||||
"failed to bind",
|
||||
"host",
|
||||
host,
|
||||
"port",
|
||||
std::to_string(desired_port),
|
||||
"errno",
|
||||
std::to_string(err),
|
||||
}));
|
||||
return; // abort constructor on non-EADDRINUSE errors
|
||||
}
|
||||
|
||||
if (std::chrono::steady_clock::now() >= deadline) {
|
||||
utils::error::raise_error(function_name,
|
||||
utils::error::create_error_message({
|
||||
"bind timeout (port in use)",
|
||||
"host",
|
||||
host,
|
||||
"port",
|
||||
std::to_string(desired_port),
|
||||
}));
|
||||
return; // abort constructor on timeout
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(250ms);
|
||||
}
|
||||
|
||||
std::thread([this]() {
|
||||
for (const auto &[prov, names] : config_->get_auto_start_list()) {
|
||||
for (const auto &name : names) {
|
||||
try {
|
||||
auto location = config_->get_mount_location(prov, name);
|
||||
if (location.empty()) {
|
||||
utils::error::raise_error(function_name,
|
||||
utils::error::create_error_message({
|
||||
"failed to auto-mount",
|
||||
"provider",
|
||||
provider_type_to_string(prov),
|
||||
"name",
|
||||
name,
|
||||
"location is empty",
|
||||
}));
|
||||
} else if (not mount(prov, name, location)) {
|
||||
utils::error::raise_error(function_name,
|
||||
utils::error::create_error_message({
|
||||
"failed to auto-mount",
|
||||
"provider",
|
||||
provider_type_to_string(prov),
|
||||
"name",
|
||||
name,
|
||||
"mount failed",
|
||||
}));
|
||||
}
|
||||
} catch (const std::exception &e) {
|
||||
utils::error::raise_error(function_name, e,
|
||||
utils::error::create_error_message({
|
||||
"failed to auto-mount",
|
||||
"provider",
|
||||
provider_type_to_string(prov),
|
||||
"name",
|
||||
name,
|
||||
}));
|
||||
} catch (...) {
|
||||
utils::error::raise_error(function_name, "unknown error",
|
||||
utils::error::create_error_message({
|
||||
"failed to auto-mount",
|
||||
"provider",
|
||||
provider_type_to_string(prov),
|
||||
"name",
|
||||
name,
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
}).join();
|
||||
|
||||
nonce_thread_ =
|
||||
std::make_unique<std::thread>([this]() { removed_expired_nonces(); });
|
||||
|
||||
server_->listen_after_bind();
|
||||
}
|
||||
|
||||
quit_handler(SIGTERM);
|
||||
}
|
||||
|
||||
handlers::~handlers() {
|
||||
if (nonce_thread_) {
|
||||
stop_requested = true;
|
||||
ui_server::~ui_server() { stop(); }
|
||||
|
||||
unique_mutex_lock lock(nonce_mtx_);
|
||||
nonce_notify_.notify_all();
|
||||
lock.unlock();
|
||||
|
||||
nonce_thread_->join();
|
||||
nonce_thread_.reset();
|
||||
}
|
||||
|
||||
event_system::instance().stop();
|
||||
}
|
||||
|
||||
auto handlers::data_directory_exists(provider_type prov,
|
||||
auto ui_server::data_directory_exists(provider_type prov,
|
||||
std::string_view name) const -> bool {
|
||||
auto data_dir = utils::path::combine(app_config::get_root_data_directory(),
|
||||
{
|
||||
@@ -428,14 +283,14 @@ auto handlers::data_directory_exists(provider_type prov,
|
||||
return ret;
|
||||
}
|
||||
|
||||
unique_mutex_lock lock(mtx_);
|
||||
unique_mutex_lock nonce_lock(mtx_);
|
||||
mtx_lookup_.erase(
|
||||
fmt::format("{}-{}", name, app_config::get_provider_name(prov)));
|
||||
lock.unlock();
|
||||
nonce_lock.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void handlers::generate_config(provider_type prov, std::string_view name,
|
||||
void ui_server::generate_config(provider_type prov, std::string_view name,
|
||||
const json &cfg,
|
||||
std::optional<std::string> data_dir) const {
|
||||
REPERTORY_USES_FUNCTION_NAME();
|
||||
@@ -484,7 +339,7 @@ void handlers::generate_config(provider_type prov, std::string_view name,
|
||||
}
|
||||
}
|
||||
|
||||
void handlers::handle_put_mount_auto_start(const httplib::Request &req,
|
||||
void ui_server::handle_put_mount_auto_start(const httplib::Request &req,
|
||||
httplib::Response &res) const {
|
||||
auto prov = provider_type_from_string(req.get_param_value("type"));
|
||||
auto name = req.get_param_value("name");
|
||||
@@ -499,7 +354,7 @@ void handlers::handle_put_mount_auto_start(const httplib::Request &req,
|
||||
res.status = http_error_codes::ok;
|
||||
}
|
||||
|
||||
void handlers::handle_put_mount_location(const httplib::Request &req,
|
||||
void ui_server::handle_put_mount_location(const httplib::Request &req,
|
||||
httplib::Response &res) const {
|
||||
auto prov = provider_type_from_string(req.get_param_value("type"));
|
||||
auto name = req.get_param_value("name");
|
||||
@@ -514,7 +369,7 @@ void handlers::handle_put_mount_location(const httplib::Request &req,
|
||||
res.status = http_error_codes::ok;
|
||||
}
|
||||
|
||||
void handlers::handle_get_available_locations(httplib::Response &res) {
|
||||
void ui_server::handle_get_available_locations(httplib::Response &res) {
|
||||
#if defined(_WIN32)
|
||||
constexpr std::array<std::string_view, 26U> letters{
|
||||
"a:", "b:", "c:", "d:", "e:", "f:", "g:", "h:", "i:",
|
||||
@@ -543,7 +398,7 @@ void handlers::handle_get_available_locations(httplib::Response &res) {
|
||||
res.status = http_error_codes::ok;
|
||||
}
|
||||
|
||||
void handlers::handle_get_mount(const httplib::Request &req,
|
||||
void ui_server::handle_get_mount(const httplib::Request &req,
|
||||
httplib::Response &res) const {
|
||||
REPERTORY_USES_FUNCTION_NAME();
|
||||
|
||||
@@ -572,7 +427,7 @@ void handlers::handle_get_mount(const httplib::Request &req,
|
||||
res.status = http_error_codes::ok;
|
||||
}
|
||||
|
||||
void handlers::handle_get_mount_list(httplib::Response &res) {
|
||||
void ui_server::handle_get_mount_list(httplib::Response &res) {
|
||||
auto data_dir = utils::file::directory{app_config::get_root_data_directory()};
|
||||
|
||||
nlohmann::json result;
|
||||
@@ -601,7 +456,7 @@ void handlers::handle_get_mount_list(httplib::Response &res) {
|
||||
res.status = http_error_codes::ok;
|
||||
}
|
||||
|
||||
void handlers::handle_get_mount_location(const httplib::Request &req,
|
||||
void ui_server::handle_get_mount_location(const httplib::Request &req,
|
||||
httplib::Response &res) const {
|
||||
auto name = req.get_param_value("name");
|
||||
auto prov = provider_type_from_string(req.get_param_value("type"));
|
||||
@@ -620,7 +475,7 @@ void handlers::handle_get_mount_location(const httplib::Request &req,
|
||||
res.status = http_error_codes::ok;
|
||||
}
|
||||
|
||||
void handlers::handle_get_mount_status(const httplib::Request &req,
|
||||
void ui_server::handle_get_mount_status(const httplib::Request &req,
|
||||
httplib::Response &res) const {
|
||||
auto name = req.get_param_value("name");
|
||||
auto prov = provider_type_from_string(req.get_param_value("type"));
|
||||
@@ -646,8 +501,8 @@ void handlers::handle_get_mount_status(const httplib::Request &req,
|
||||
res.status = http_error_codes::ok;
|
||||
}
|
||||
|
||||
void handlers::handle_get_nonce(httplib::Response &res) {
|
||||
mutex_lock lock(nonce_mtx_);
|
||||
void ui_server::handle_get_nonce(httplib::Response &res) {
|
||||
mutex_lock nonce_lock(nonce_mtx_);
|
||||
|
||||
nonce_data nonce{};
|
||||
nonce_lookup_[nonce.nonce] = nonce;
|
||||
@@ -657,7 +512,7 @@ void handlers::handle_get_nonce(httplib::Response &res) {
|
||||
res.status = http_error_codes::ok;
|
||||
}
|
||||
|
||||
void handlers::handle_get_settings(httplib::Response &res) const {
|
||||
void ui_server::handle_get_settings(httplib::Response &res) const {
|
||||
auto settings = config_->to_json();
|
||||
settings[JSON_API_PASSWORD] = "";
|
||||
settings.erase(JSON_MOUNT_LOCATIONS);
|
||||
@@ -665,18 +520,18 @@ void handlers::handle_get_settings(httplib::Response &res) const {
|
||||
res.status = http_error_codes::ok;
|
||||
}
|
||||
|
||||
void handlers::handle_get_test(const httplib::Request &req,
|
||||
void ui_server::handle_get_test(const httplib::Request &req,
|
||||
httplib::Response &res) const {
|
||||
REPERTORY_USES_FUNCTION_NAME();
|
||||
|
||||
unique_mutex_lock lock(test_mtx_);
|
||||
unique_mutex_lock nonce_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")});
|
||||
utils::directory::temp(), {utils::file::create_temp_name(REPERTORY)});
|
||||
|
||||
try {
|
||||
generate_config(prov, name, cfg, data_dir);
|
||||
@@ -698,7 +553,7 @@ void handlers::handle_get_test(const httplib::Request &req,
|
||||
fmt::format("failed to remove data directory|{}", data_dir));
|
||||
}
|
||||
|
||||
void handlers::handle_post_add_mount(const httplib::Request &req,
|
||||
void ui_server::handle_post_add_mount(const httplib::Request &req,
|
||||
httplib::Response &res) const {
|
||||
auto name = req.get_param_value("name");
|
||||
auto prov = provider_type_from_string(req.get_param_value("type"));
|
||||
@@ -713,7 +568,7 @@ void handlers::handle_post_add_mount(const httplib::Request &req,
|
||||
res.status = http_error_codes::ok;
|
||||
}
|
||||
|
||||
void handlers::handle_post_mount(const httplib::Request &req,
|
||||
void ui_server::handle_post_mount(const httplib::Request &req,
|
||||
httplib::Response &res) {
|
||||
auto name = req.get_param_value("name");
|
||||
auto prov = provider_type_from_string(req.get_param_value("type"));
|
||||
@@ -740,7 +595,7 @@ void handlers::handle_post_mount(const httplib::Request &req,
|
||||
res.status = http_error_codes::internal_error;
|
||||
}
|
||||
|
||||
void handlers::handle_put_set_value_by_name(const httplib::Request &req,
|
||||
void ui_server::handle_put_set_value_by_name(const httplib::Request &req,
|
||||
httplib::Response &res) const {
|
||||
auto name = req.get_param_value("name");
|
||||
auto prov = provider_type_from_string(req.get_param_value("type"));
|
||||
@@ -762,7 +617,7 @@ void handlers::handle_put_set_value_by_name(const httplib::Request &req,
|
||||
res.status = http_error_codes::ok;
|
||||
}
|
||||
|
||||
void handlers::handle_put_setting(const httplib::Request &req,
|
||||
void ui_server::handle_put_setting(const httplib::Request &req,
|
||||
httplib::Response &res) const {
|
||||
auto name = req.get_param_value("name");
|
||||
auto value = req.get_param_value("value");
|
||||
@@ -776,7 +631,7 @@ void handlers::handle_put_setting(const httplib::Request &req,
|
||||
res.status = http_error_codes::ok;
|
||||
}
|
||||
|
||||
void handlers::handle_put_settings(const httplib::Request &req,
|
||||
void ui_server::handle_put_settings(const httplib::Request &req,
|
||||
httplib::Response &res) const {
|
||||
auto data = nlohmann::json::parse(req.get_param_value("data"));
|
||||
|
||||
@@ -800,7 +655,7 @@ void handlers::handle_put_settings(const httplib::Request &req,
|
||||
res.status = http_error_codes::ok;
|
||||
}
|
||||
|
||||
auto handlers::launch_process(provider_type prov, std::string_view name,
|
||||
auto ui_server::launch_process(provider_type prov, std::string_view name,
|
||||
std::vector<std::string> args,
|
||||
bool background) const
|
||||
-> std::vector<std::string> {
|
||||
@@ -840,10 +695,10 @@ auto handlers::launch_process(provider_type prov, std::string_view name,
|
||||
});
|
||||
}
|
||||
|
||||
unique_mutex_lock lock(mtx_);
|
||||
unique_mutex_lock nonce_lock(mtx_);
|
||||
auto &inst_mtx = mtx_lookup_[fmt::format(
|
||||
"{}-{}", name, app_config::get_provider_name(prov))];
|
||||
lock.unlock();
|
||||
nonce_lock.unlock();
|
||||
|
||||
recur_mutex_lock inst_lock(inst_mtx);
|
||||
if (background) {
|
||||
@@ -912,7 +767,7 @@ auto handlers::launch_process(provider_type prov, std::string_view name,
|
||||
false);
|
||||
}
|
||||
|
||||
auto handlers::mount(provider_type prov, std::string_view name,
|
||||
auto ui_server::mount(provider_type prov, std::string_view name,
|
||||
const std::string &location) -> bool {
|
||||
#if defined(_WIN32)
|
||||
if (utils::file::directory{location}.exists()) {
|
||||
@@ -927,28 +782,33 @@ auto handlers::mount(provider_type prov, std::string_view name,
|
||||
config_->set_mount_location(prov, name, location);
|
||||
|
||||
static std::mutex mount_mtx;
|
||||
mutex_lock lock(mount_mtx);
|
||||
mutex_lock nonce_lock(mount_mtx);
|
||||
|
||||
launch_process(prov, name, {location}, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
void handlers::removed_expired_nonces() {
|
||||
unique_mutex_lock lock(nonce_mtx_);
|
||||
lock.unlock();
|
||||
void ui_server::notify_and_unlock(unique_mutex_lock &nonce_lock) {
|
||||
nonce_notify_.notify_all();
|
||||
nonce_lock.unlock();
|
||||
}
|
||||
|
||||
void ui_server::removed_expired_nonces() {
|
||||
unique_mutex_lock nonce_lock(nonce_mtx_);
|
||||
notify_and_unlock(nonce_lock);
|
||||
|
||||
while (not stop_requested) {
|
||||
lock.lock();
|
||||
nonce_lock.lock();
|
||||
auto nonces = nonce_lookup_;
|
||||
lock.unlock();
|
||||
notify_and_unlock(nonce_lock);
|
||||
|
||||
for (const auto &[key, value] : nonces) {
|
||||
if (std::chrono::duration_cast<std::chrono::seconds>(
|
||||
std::chrono::system_clock::now() - value.creation)
|
||||
.count() >= nonce_timeout) {
|
||||
lock.lock();
|
||||
nonce_lock.lock();
|
||||
nonce_lookup_.erase(key);
|
||||
lock.unlock();
|
||||
notify_and_unlock(nonce_lock);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -956,16 +816,16 @@ void handlers::removed_expired_nonces() {
|
||||
break;
|
||||
}
|
||||
|
||||
lock.lock();
|
||||
nonce_lock.lock();
|
||||
if (stop_requested) {
|
||||
break;
|
||||
}
|
||||
nonce_notify_.wait_for(lock, std::chrono::seconds(1U));
|
||||
lock.unlock();
|
||||
nonce_notify_.wait_for(nonce_lock, std::chrono::seconds(1U));
|
||||
notify_and_unlock(nonce_lock);
|
||||
}
|
||||
}
|
||||
|
||||
void handlers::set_key_value(provider_type prov, std::string_view name,
|
||||
void ui_server::set_key_value(provider_type prov, std::string_view name,
|
||||
std::string_view key, std::string_view value,
|
||||
std::optional<std::string> data_dir) const {
|
||||
std::vector<std::string> args;
|
||||
@@ -978,4 +838,160 @@ void handlers::set_key_value(provider_type prov, std::string_view name,
|
||||
args.emplace_back(value);
|
||||
launch_process(prov, name, args, false);
|
||||
}
|
||||
|
||||
void ui_server::start() {
|
||||
REPERTORY_USES_FUNCTION_NAME();
|
||||
|
||||
unique_mutex_lock nonce_lock(nonce_mtx_);
|
||||
if (nonce_thread_) {
|
||||
return;
|
||||
}
|
||||
|
||||
stop_requested = false;
|
||||
event_system::instance().start();
|
||||
|
||||
nonce_thread_ =
|
||||
std::make_unique<std::thread>([this]() { removed_expired_nonces(); });
|
||||
|
||||
const auto launch_ui = [this]() {
|
||||
if (not config_->get_launch_only()) {
|
||||
#if defined(_WIN32)
|
||||
system(
|
||||
fmt::format(
|
||||
R"(start "Repertory Management Portal" "http://127.0.0.1:{}/ui")",
|
||||
config_->get_api_port())
|
||||
.c_str());
|
||||
#elif defined(__linux__)
|
||||
system(fmt::format(R"(xdg-open "http://127.0.0.1:{}/ui")",
|
||||
config_->get_api_port())
|
||||
.c_str());
|
||||
#elif defined(__APPLE__)
|
||||
system(fmt::format(R"(open "http://127.0.0.1:{}/ui")",
|
||||
config_->get_api_port())
|
||||
.c_str());
|
||||
#else
|
||||
build fails here
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
auto should_launch{true};
|
||||
|
||||
lock_data ui_lock(provider_type::unknown, "ui");
|
||||
auto res = ui_lock.grab_lock(1U);
|
||||
if (res == lock_result::locked) {
|
||||
auto deadline{std::chrono::steady_clock::now() + 30s};
|
||||
std::string host{"127.0.0.1"};
|
||||
auto desired_port{config_->get_api_port()};
|
||||
|
||||
auto success{false};
|
||||
while (not success && std::chrono::steady_clock::now() >= deadline) {
|
||||
success = server_.bind_to_port(host, desired_port);
|
||||
if (success) {
|
||||
break;
|
||||
}
|
||||
|
||||
utils::error::raise_error(function_name,
|
||||
utils::error::create_error_message({
|
||||
"failed to bind",
|
||||
"host",
|
||||
host,
|
||||
"port",
|
||||
std::to_string(desired_port),
|
||||
"error",
|
||||
std::to_string(get_last_net_error()),
|
||||
}));
|
||||
std::this_thread::sleep_for(250ms);
|
||||
}
|
||||
|
||||
if (success) {
|
||||
std::thread([this]() {
|
||||
for (const auto &[prov, names] : config_->get_auto_start_list()) {
|
||||
for (const auto &name : names) {
|
||||
try {
|
||||
auto location = config_->get_mount_location(prov, name);
|
||||
if (location.empty()) {
|
||||
utils::error::raise_error(function_name,
|
||||
utils::error::create_error_message({
|
||||
"failed to auto-mount",
|
||||
"provider",
|
||||
provider_type_to_string(prov),
|
||||
"name",
|
||||
name,
|
||||
"location is empty",
|
||||
}));
|
||||
} else if (not mount(prov, name, location)) {
|
||||
utils::error::raise_error(function_name,
|
||||
utils::error::create_error_message({
|
||||
"failed to auto-mount",
|
||||
"provider",
|
||||
provider_type_to_string(prov),
|
||||
"name",
|
||||
name,
|
||||
"mount failed",
|
||||
}));
|
||||
}
|
||||
} catch (const std::exception &e) {
|
||||
utils::error::raise_error(function_name, e,
|
||||
utils::error::create_error_message({
|
||||
"failed to auto-mount",
|
||||
"provider",
|
||||
provider_type_to_string(prov),
|
||||
"name",
|
||||
name,
|
||||
}));
|
||||
} catch (...) {
|
||||
utils::error::raise_error(function_name, "unknown error",
|
||||
utils::error::create_error_message({
|
||||
"failed to auto-mount",
|
||||
"provider",
|
||||
provider_type_to_string(prov),
|
||||
"name",
|
||||
name,
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
}).join();
|
||||
|
||||
server_.listen_after_bind();
|
||||
} else {
|
||||
utils::error::raise_error(function_name,
|
||||
utils::error::create_error_message({
|
||||
"bind timeout (port in use)",
|
||||
"host",
|
||||
host,
|
||||
"port",
|
||||
std::to_string(desired_port),
|
||||
}));
|
||||
should_launch = false;
|
||||
}
|
||||
}
|
||||
|
||||
notify_and_unlock(nonce_lock);
|
||||
if (not should_launch) {
|
||||
return;
|
||||
}
|
||||
|
||||
launch_ui();
|
||||
}
|
||||
|
||||
void ui_server::stop() {
|
||||
unique_mutex_lock nonce_lock(nonce_mtx_);
|
||||
if (not nonce_thread_) {
|
||||
notify_and_unlock(nonce_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
stop_requested = true;
|
||||
notify_and_unlock(nonce_lock);
|
||||
|
||||
nonce_thread_->join();
|
||||
|
||||
nonce_lock.lock();
|
||||
nonce_thread_.reset();
|
||||
notify_and_unlock(nonce_lock);
|
||||
|
||||
event_system::instance().stop();
|
||||
}
|
||||
} // namespace repertory::ui
|
@@ -27,7 +27,7 @@
|
||||
namespace repertory {
|
||||
TEST(curl_comm_test, can_create_s3_host_config) {
|
||||
s3_config config{};
|
||||
config.bucket = "repertory";
|
||||
config.bucket = REPERTORY;
|
||||
config.url = "https://s3.test.com";
|
||||
config.region = "any";
|
||||
config.use_path_style = false;
|
||||
@@ -40,7 +40,7 @@ TEST(curl_comm_test, can_create_s3_host_config) {
|
||||
|
||||
TEST(curl_comm_test, can_create_s3_host_config_with_path_style) {
|
||||
s3_config config{};
|
||||
config.bucket = "repertory";
|
||||
config.bucket = REPERTORY;
|
||||
config.url = "https://s3.test.com";
|
||||
config.region = "any";
|
||||
config.use_path_style = true;
|
||||
@@ -53,7 +53,7 @@ TEST(curl_comm_test, can_create_s3_host_config_with_path_style) {
|
||||
|
||||
TEST(curl_comm_test, can_create_s3_host_config_with_region) {
|
||||
s3_config config{};
|
||||
config.bucket = "repertory";
|
||||
config.bucket = REPERTORY;
|
||||
config.url = "https://s3.test.com";
|
||||
config.region = "any";
|
||||
config.use_region_in_url = true;
|
||||
@@ -67,7 +67,7 @@ TEST(curl_comm_test, can_create_s3_host_config_with_region) {
|
||||
|
||||
TEST(curl_comm_test, can_create_s3_host_config_with_region_and_path_style) {
|
||||
s3_config config{};
|
||||
config.bucket = "repertory";
|
||||
config.bucket = REPERTORY;
|
||||
config.url = "https://s3.test.com";
|
||||
config.region = "any";
|
||||
config.use_region_in_url = true;
|
||||
|
Reference in New Issue
Block a user