broken build - [refactor ui start/stop][prefer REPERTORY/REPERTORY_W]
This commit is contained in:
@@ -447,7 +447,7 @@ auto fuse_base::mount([[maybe_unused]] std::vector<std::string> orig_args,
|
|||||||
return -1;
|
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");
|
orig_args.insert(std::next(orig_args.begin()), "-f");
|
||||||
|
|
||||||
utils::plist_cfg cfg{};
|
utils::plist_cfg cfg{};
|
||||||
|
@@ -36,9 +36,9 @@ private:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
std::atomic<bool> animations_{true};
|
std::atomic<bool> animations_{true};
|
||||||
utils::atomic<std::string> api_password_{"repertory"};
|
utils::atomic<std::string> api_password_{REPERTORY};
|
||||||
std::atomic<std::uint16_t> api_port_{default_ui_mgmt_port};
|
std::atomic<std::uint16_t> api_port_{default_ui_mgmt_port};
|
||||||
utils::atomic<std::string> api_user_{"repertory"};
|
utils::atomic<std::string> api_user_{REPERTORY};
|
||||||
std::atomic<bool> auto_start_{true};
|
std::atomic<bool> auto_start_{true};
|
||||||
std::unordered_map<provider_type,
|
std::unordered_map<provider_type,
|
||||||
std::unordered_map<std::string, std::string>>
|
std::unordered_map<std::string, std::string>>
|
||||||
|
@@ -19,16 +19,17 @@
|
|||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
*/
|
*/
|
||||||
#ifndef REPERTORY_INCLUDE_UI_HANDLERS_HPP_
|
#ifndef REPERTORY_INCLUDE_UI_SERVER_HPP_
|
||||||
#define REPERTORY_INCLUDE_UI_HANDLERS_HPP_
|
#define REPERTORY_INCLUDE_UI_SERVER_HPP_
|
||||||
|
|
||||||
#include "events/consumers/console_consumer.hpp"
|
#include "events/consumers/console_consumer.hpp"
|
||||||
|
#include "events/consumers/logging_consumer.hpp"
|
||||||
#include "utils/common.hpp"
|
#include "utils/common.hpp"
|
||||||
|
|
||||||
namespace repertory::ui {
|
namespace repertory::ui {
|
||||||
class mgmt_app_config;
|
class mgmt_app_config;
|
||||||
|
|
||||||
class handlers final {
|
class ui_server final {
|
||||||
private:
|
private:
|
||||||
static constexpr auto nonce_length{128U};
|
static constexpr auto nonce_length{128U};
|
||||||
static constexpr auto nonce_timeout{15U};
|
static constexpr auto nonce_timeout{15U};
|
||||||
@@ -44,21 +45,21 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
handlers(mgmt_app_config *config, httplib::Server *server);
|
ui_server(mgmt_app_config *config);
|
||||||
|
|
||||||
handlers() = delete;
|
ui_server() = delete;
|
||||||
handlers(const handlers &) = delete;
|
ui_server(const ui_server &) = delete;
|
||||||
handlers(handlers &&) = delete;
|
ui_server(ui_server &&) = delete;
|
||||||
|
|
||||||
~handlers();
|
~ui_server();
|
||||||
|
|
||||||
auto operator=(const handlers &) -> handlers & = delete;
|
auto operator=(const ui_server &) -> ui_server & = delete;
|
||||||
auto operator=(handlers &&) -> handlers & = delete;
|
auto operator=(ui_server &&) -> ui_server & = delete;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
mgmt_app_config *config_;
|
mgmt_app_config *config_;
|
||||||
|
logging_consumer logging;
|
||||||
std::string repertory_binary_;
|
std::string repertory_binary_;
|
||||||
httplib::Server *server_;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
console_consumer console;
|
console_consumer console;
|
||||||
@@ -68,6 +69,7 @@ private:
|
|||||||
std::unordered_map<std::string, nonce_data> nonce_lookup_;
|
std::unordered_map<std::string, nonce_data> nonce_lookup_;
|
||||||
std::condition_variable nonce_notify_;
|
std::condition_variable nonce_notify_;
|
||||||
std::unique_ptr<std::thread> nonce_thread_;
|
std::unique_ptr<std::thread> nonce_thread_;
|
||||||
|
httplib::Server server_;
|
||||||
stop_type stop_requested{false};
|
stop_type stop_requested{false};
|
||||||
mutable std::mutex test_mtx_;
|
mutable std::mutex test_mtx_;
|
||||||
|
|
||||||
@@ -127,12 +129,19 @@ private:
|
|||||||
[[nodiscard]] auto mount(provider_type prov, std::string_view name,
|
[[nodiscard]] auto mount(provider_type prov, std::string_view name,
|
||||||
const std::string &location) -> bool;
|
const std::string &location) -> bool;
|
||||||
|
|
||||||
|
void notify_and_unlock(unique_mutex_lock &nonce_lock);
|
||||||
|
|
||||||
void removed_expired_nonces();
|
void removed_expired_nonces();
|
||||||
|
|
||||||
void set_key_value(provider_type prov, std::string_view name,
|
void set_key_value(provider_type prov, std::string_view name,
|
||||||
std::string_view key, std::string_view value,
|
std::string_view key, std::string_view value,
|
||||||
std::optional<std::string> data_dir = std::nullopt) const;
|
std::optional<std::string> data_dir = std::nullopt) const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void start();
|
||||||
|
|
||||||
|
void stop();
|
||||||
};
|
};
|
||||||
} // namespace repertory::ui
|
} // namespace repertory::ui
|
||||||
|
|
||||||
#endif // REPERTORY_INCLUDE_UI_HANDLERS_HPP_
|
#endif // REPERTORY_INCLUDE_UI_SERVER_HPP_
|
@@ -26,8 +26,8 @@
|
|||||||
#include "cli/actions.hpp"
|
#include "cli/actions.hpp"
|
||||||
#include "initialize.hpp"
|
#include "initialize.hpp"
|
||||||
#include "types/repertory.hpp"
|
#include "types/repertory.hpp"
|
||||||
#include "ui/handlers.hpp"
|
|
||||||
#include "ui/mgmt_app_config.hpp"
|
#include "ui/mgmt_app_config.hpp"
|
||||||
|
#include "ui/ui_server.hpp"
|
||||||
#include "utils/cli_utils.hpp"
|
#include "utils/cli_utils.hpp"
|
||||||
#include "utils/polling.hpp"
|
#include "utils/polling.hpp"
|
||||||
|
|
||||||
@@ -80,18 +80,51 @@ auto main(int argc, char **argv) -> int {
|
|||||||
if (not utils::file::change_to_process_directory()) {
|
if (not utils::file::change_to_process_directory()) {
|
||||||
ret = static_cast<std::int32_t>(exit_code::ui_failed);
|
ret = static_cast<std::int32_t>(exit_code::ui_failed);
|
||||||
} else {
|
} else {
|
||||||
httplib::Server server;
|
const auto run_ui = [](auto *server) {
|
||||||
#if defined(__APPLE__)
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
if (not server.set_mount_point("/ui", "../Resources/web")) {
|
|
||||||
#else // !defined(__APPLE__)
|
static std::atomic<ui::server *> active_server{server};
|
||||||
if (not server.set_mount_point("/ui", "./web")) {
|
static const auto quit_handler = [](int /* sig */) {
|
||||||
#endif // defined(__APPLE__)
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
ret = static_cast<std::int32_t>(exit_code::ui_failed);
|
|
||||||
} else {
|
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 {
|
||||||
|
ptr->start();
|
||||||
|
} catch (const std::exception &ex) {
|
||||||
|
utils::error::raise_error(function_name, ex, "failed to start ui");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
ptr->stop();
|
||||||
|
} catch (const std::exception &ex) {
|
||||||
|
utils::error::raise_error(function_name, ex, "failed to stop ui");
|
||||||
|
}
|
||||||
|
|
||||||
|
repertory::project_cleanup();
|
||||||
|
};
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
ui::handlers handlers(&config, &server);
|
ui::server server(&config);
|
||||||
|
run_ui(&server);
|
||||||
#else // !defined(_WIN32)
|
#else // !defined(_WIN32)
|
||||||
project_cleanup();
|
repertory::project_cleanup();
|
||||||
|
|
||||||
ret = utils::create_daemon([&]() -> int {
|
ret = utils::create_daemon([&]() -> int {
|
||||||
if (not repertory::project_initialize()) {
|
if (not repertory::project_initialize()) {
|
||||||
@@ -103,13 +136,12 @@ auto main(int argc, char **argv) -> int {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ui::handlers handlers(&config, &server);
|
ui::server server(&config);
|
||||||
project_cleanup();
|
run_ui(&server);
|
||||||
return 0;
|
return 0;
|
||||||
});
|
});
|
||||||
#endif // defined(_WIN32)
|
#endif // defined(_WIN32)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
auto prov = utils::cli::get_provider_type_from_args(args);
|
auto prov = utils::cli::get_provider_type_from_args(args);
|
||||||
|
|
||||||
|
@@ -249,11 +249,11 @@ void mgmt_app_config::set_auto_start(bool auto_start) {
|
|||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
if (auto_start) {
|
if (auto_start) {
|
||||||
utils::autostart_cfg cfg{};
|
utils::autostart_cfg cfg{};
|
||||||
cfg.app_name = "repertory";
|
cfg.app_name = REPERTORY;
|
||||||
cfg.comment = "Mount utility for AWS S3 and Sia";
|
cfg.comment = "Mount utility for AWS S3 and Sia";
|
||||||
cfg.exec_args = {"-ui", "-lo"};
|
cfg.exec_args = {"-ui", "-lo"};
|
||||||
cfg.exec_path = utils::path::combine(".", {"repertory"});
|
cfg.exec_path = utils::path::combine(".", {REPERTORY});
|
||||||
cfg.icon_path = utils::path::combine(".", {"repertory.png"});
|
cfg.icon_path = utils::path::combine(".", {REPERTORY ".png"});
|
||||||
cfg.terminal = true;
|
cfg.terminal = true;
|
||||||
|
|
||||||
if (utils::create_autostart_entry(cfg, false)) {
|
if (utils::create_autostart_entry(cfg, false)) {
|
||||||
@@ -264,7 +264,7 @@ void mgmt_app_config::set_auto_start(bool auto_start) {
|
|||||||
function_name, utils::get_last_error_code(),
|
function_name, utils::get_last_error_code(),
|
||||||
"failed to create auto-start entry|name|repertory");
|
"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,
|
utils::error::handle_info(function_name,
|
||||||
"removed auto-start entry|name|repertory");
|
"removed auto-start entry|name|repertory");
|
||||||
} else {
|
} else {
|
||||||
@@ -278,9 +278,9 @@ void mgmt_app_config::set_auto_start(bool auto_start) {
|
|||||||
if (auto_start) {
|
if (auto_start) {
|
||||||
utils::shortcut_cfg cfg{};
|
utils::shortcut_cfg cfg{};
|
||||||
cfg.arguments = L"-ui -lo --hidden";
|
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.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".");
|
cfg.working_directory = utils::path::absolute(L".");
|
||||||
|
|
||||||
if (utils::create_shortcut(cfg, false)) {
|
if (utils::create_shortcut(cfg, false)) {
|
||||||
@@ -291,7 +291,7 @@ void mgmt_app_config::set_auto_start(bool auto_start) {
|
|||||||
function_name, utils::get_last_error_code(),
|
function_name, utils::get_last_error_code(),
|
||||||
"failed to create auto-start entry|name|repertory");
|
"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,
|
utils::error::handle_info(function_name,
|
||||||
"removed auto-start entry|name|repertory");
|
"removed auto-start entry|name|repertory");
|
||||||
} else {
|
} else {
|
||||||
@@ -307,7 +307,7 @@ void mgmt_app_config::set_auto_start(bool auto_start) {
|
|||||||
if (auto_start) {
|
if (auto_start) {
|
||||||
utils::plist_cfg cfg{};
|
utils::plist_cfg cfg{};
|
||||||
cfg.args = {
|
cfg.args = {
|
||||||
utils::path::combine(".", {"repertory"}),
|
utils::path::combine(".", {REPERTORY}),
|
||||||
"-ui",
|
"-ui",
|
||||||
"-lo",
|
"-lo",
|
||||||
};
|
};
|
||||||
|
@@ -19,9 +19,11 @@
|
|||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
*/
|
*/
|
||||||
#include "ui/handlers.hpp"
|
#include "ui/ui_server.hpp"
|
||||||
|
|
||||||
#include "app_config.hpp"
|
#include "app_config.hpp"
|
||||||
|
#include "events/consumers/console_consumer.hpp"
|
||||||
|
#include "events/consumers/logging_consumer.hpp"
|
||||||
#include "events/event_system.hpp"
|
#include "events/event_system.hpp"
|
||||||
#include "platform/platform.hpp"
|
#include "platform/platform.hpp"
|
||||||
#include "types/repertory.hpp"
|
#include "types/repertory.hpp"
|
||||||
@@ -120,43 +122,27 @@ namespace {
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace repertory::ui {
|
namespace repertory::ui {
|
||||||
handlers::handlers(mgmt_app_config *config, httplib::Server *server)
|
ui_server::ui_server(mgmt_app_config *config)
|
||||||
: config_(config),
|
: config_(config),
|
||||||
|
logging(config->get_event_level(),
|
||||||
|
utils::path::combine(app_config::get_root_data_directory(),
|
||||||
|
{
|
||||||
|
"ui",
|
||||||
|
"logs",
|
||||||
|
})),
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
repertory_binary_(utils::path::combine(".", {"repertory.exe"})),
|
repertory_binary_(utils::path::combine(".", {REPERTORY ".exe"}))
|
||||||
#else // !defined(_WIN32)
|
#else // !defined(_WIN32)
|
||||||
repertory_binary_(utils::path::combine(".", {"repertory"})),
|
repertory_binary_(utils::path::combine(".", {REPERTORY}))
|
||||||
#endif // defined(_WIN32)
|
#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)
|
server_.set_socket_options([](auto &&sock) {
|
||||||
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) {
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
BOOL enable = TRUE;
|
BOOL enable = TRUE;
|
||||||
::setsockopt(sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
|
::setsockopt(sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
|
||||||
@@ -176,7 +162,7 @@ handlers::handlers(mgmt_app_config *config, httplib::Server *server)
|
|||||||
#endif
|
#endif
|
||||||
});
|
});
|
||||||
|
|
||||||
server_->set_pre_routing_handler(
|
server_.set_pre_routing_handler(
|
||||||
[this](const httplib::Request &req,
|
[this](const httplib::Request &req,
|
||||||
auto &&res) -> httplib::Server::HandlerResponse {
|
auto &&res) -> httplib::Server::HandlerResponse {
|
||||||
if (req.path == "/api/v1/nonce" || req.path == "/ui" ||
|
if (req.path == "/api/v1/nonce" || req.path == "/ui" ||
|
||||||
@@ -190,7 +176,7 @@ handlers::handlers(mgmt_app_config *config, httplib::Server *server)
|
|||||||
auth, fmt::format("{}_", config_->get_api_user()))) {
|
auth, fmt::format("{}_", config_->get_api_user()))) {
|
||||||
auto nonce = auth.substr(config_->get_api_user().length() + 1U);
|
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)) {
|
if (nonce_lookup_.contains(nonce)) {
|
||||||
nonce_lookup_.erase(nonce);
|
nonce_lookup_.erase(nonce);
|
||||||
return httplib::Server::HandlerResponse::Unhandled;
|
return httplib::Server::HandlerResponse::Unhandled;
|
||||||
@@ -201,9 +187,11 @@ handlers::handlers(mgmt_app_config *config, httplib::Server *server)
|
|||||||
return httplib::Server::HandlerResponse::Handled;
|
return httplib::Server::HandlerResponse::Handled;
|
||||||
});
|
});
|
||||||
|
|
||||||
server_->set_exception_handler([](const httplib::Request &req,
|
server_.set_exception_handler([](const httplib::Request &req,
|
||||||
httplib::Response &res,
|
httplib::Response &res,
|
||||||
std::exception_ptr ptr) {
|
std::exception_ptr ptr) {
|
||||||
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
json data{
|
json data{
|
||||||
{"path", req.path},
|
{"path", req.path},
|
||||||
};
|
};
|
||||||
@@ -227,196 +215,71 @@ handlers::handlers(mgmt_app_config *config, httplib::Server *server)
|
|||||||
: http_error_codes::internal_error;
|
: 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);
|
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); });
|
[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);
|
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);
|
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);
|
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); });
|
[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);
|
handle_get_settings(res);
|
||||||
});
|
});
|
||||||
|
|
||||||
server->Get("/api/v1/test",
|
server_.Get("/api/v1/test",
|
||||||
[this](auto &&req, auto &&res) { handle_get_test(req, res); });
|
[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);
|
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); });
|
[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);
|
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);
|
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);
|
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); });
|
[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);
|
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)
|
#if defined(_WIN32)
|
||||||
std::jthread([ptr]() { ptr->stop(); });
|
if (config_->get_hidden()) {
|
||||||
#else // !defined(_WIN32)
|
::ShowWindow(::GetConsoleWindow(), SW_HIDE);
|
||||||
ptr->stop();
|
}
|
||||||
#endif // defined(_WIN32)
|
#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();
|
ui_server::~ui_server() { stop(); }
|
||||||
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) {
|
auto ui_server::data_directory_exists(provider_type prov,
|
||||||
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;
|
|
||||||
|
|
||||||
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,
|
|
||||||
std::string_view name) const -> bool {
|
std::string_view name) const -> bool {
|
||||||
auto data_dir = utils::path::combine(app_config::get_root_data_directory(),
|
auto data_dir = utils::path::combine(app_config::get_root_data_directory(),
|
||||||
{
|
{
|
||||||
@@ -428,14 +291,14 @@ auto handlers::data_directory_exists(provider_type prov,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
unique_mutex_lock lock(mtx_);
|
unique_mutex_lock nonce_lock(mtx_);
|
||||||
mtx_lookup_.erase(
|
mtx_lookup_.erase(
|
||||||
fmt::format("{}-{}", name, app_config::get_provider_name(prov)));
|
fmt::format("{}-{}", name, app_config::get_provider_name(prov)));
|
||||||
lock.unlock();
|
nonce_lock.unlock();
|
||||||
return ret;
|
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,
|
const json &cfg,
|
||||||
std::optional<std::string> data_dir) const {
|
std::optional<std::string> data_dir) const {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
@@ -484,7 +347,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 {
|
httplib::Response &res) const {
|
||||||
auto prov = provider_type_from_string(req.get_param_value("type"));
|
auto prov = provider_type_from_string(req.get_param_value("type"));
|
||||||
auto name = req.get_param_value("name");
|
auto name = req.get_param_value("name");
|
||||||
@@ -499,7 +362,7 @@ void handlers::handle_put_mount_auto_start(const httplib::Request &req,
|
|||||||
res.status = http_error_codes::ok;
|
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 {
|
httplib::Response &res) const {
|
||||||
auto prov = provider_type_from_string(req.get_param_value("type"));
|
auto prov = provider_type_from_string(req.get_param_value("type"));
|
||||||
auto name = req.get_param_value("name");
|
auto name = req.get_param_value("name");
|
||||||
@@ -514,7 +377,7 @@ void handlers::handle_put_mount_location(const httplib::Request &req,
|
|||||||
res.status = http_error_codes::ok;
|
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)
|
#if defined(_WIN32)
|
||||||
constexpr std::array<std::string_view, 26U> letters{
|
constexpr std::array<std::string_view, 26U> letters{
|
||||||
"a:", "b:", "c:", "d:", "e:", "f:", "g:", "h:", "i:",
|
"a:", "b:", "c:", "d:", "e:", "f:", "g:", "h:", "i:",
|
||||||
@@ -543,7 +406,7 @@ void handlers::handle_get_available_locations(httplib::Response &res) {
|
|||||||
res.status = http_error_codes::ok;
|
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 {
|
httplib::Response &res) const {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
@@ -572,7 +435,7 @@ void handlers::handle_get_mount(const httplib::Request &req,
|
|||||||
res.status = http_error_codes::ok;
|
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()};
|
auto data_dir = utils::file::directory{app_config::get_root_data_directory()};
|
||||||
|
|
||||||
nlohmann::json result;
|
nlohmann::json result;
|
||||||
@@ -601,7 +464,7 @@ void handlers::handle_get_mount_list(httplib::Response &res) {
|
|||||||
res.status = http_error_codes::ok;
|
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 {
|
httplib::Response &res) const {
|
||||||
auto name = req.get_param_value("name");
|
auto name = req.get_param_value("name");
|
||||||
auto prov = provider_type_from_string(req.get_param_value("type"));
|
auto prov = provider_type_from_string(req.get_param_value("type"));
|
||||||
@@ -620,7 +483,7 @@ void handlers::handle_get_mount_location(const httplib::Request &req,
|
|||||||
res.status = http_error_codes::ok;
|
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 {
|
httplib::Response &res) const {
|
||||||
auto name = req.get_param_value("name");
|
auto name = req.get_param_value("name");
|
||||||
auto prov = provider_type_from_string(req.get_param_value("type"));
|
auto prov = provider_type_from_string(req.get_param_value("type"));
|
||||||
@@ -646,8 +509,8 @@ void handlers::handle_get_mount_status(const httplib::Request &req,
|
|||||||
res.status = http_error_codes::ok;
|
res.status = http_error_codes::ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
void handlers::handle_get_nonce(httplib::Response &res) {
|
void ui_server::handle_get_nonce(httplib::Response &res) {
|
||||||
mutex_lock lock(nonce_mtx_);
|
mutex_lock nonce_lock(nonce_mtx_);
|
||||||
|
|
||||||
nonce_data nonce{};
|
nonce_data nonce{};
|
||||||
nonce_lookup_[nonce.nonce] = nonce;
|
nonce_lookup_[nonce.nonce] = nonce;
|
||||||
@@ -657,7 +520,7 @@ void handlers::handle_get_nonce(httplib::Response &res) {
|
|||||||
res.status = http_error_codes::ok;
|
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();
|
auto settings = config_->to_json();
|
||||||
settings[JSON_API_PASSWORD] = "";
|
settings[JSON_API_PASSWORD] = "";
|
||||||
settings.erase(JSON_MOUNT_LOCATIONS);
|
settings.erase(JSON_MOUNT_LOCATIONS);
|
||||||
@@ -665,18 +528,18 @@ void handlers::handle_get_settings(httplib::Response &res) const {
|
|||||||
res.status = http_error_codes::ok;
|
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 {
|
httplib::Response &res) const {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
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 name = req.get_param_value("name");
|
||||||
auto prov = provider_type_from_string(req.get_param_value("type"));
|
auto prov = provider_type_from_string(req.get_param_value("type"));
|
||||||
auto cfg = nlohmann::json::parse(req.get_param_value("config"));
|
auto cfg = nlohmann::json::parse(req.get_param_value("config"));
|
||||||
|
|
||||||
auto data_dir = utils::path::combine(
|
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 {
|
try {
|
||||||
generate_config(prov, name, cfg, data_dir);
|
generate_config(prov, name, cfg, data_dir);
|
||||||
@@ -698,7 +561,7 @@ void handlers::handle_get_test(const httplib::Request &req,
|
|||||||
fmt::format("failed to remove data directory|{}", data_dir));
|
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 {
|
httplib::Response &res) const {
|
||||||
auto name = req.get_param_value("name");
|
auto name = req.get_param_value("name");
|
||||||
auto prov = provider_type_from_string(req.get_param_value("type"));
|
auto prov = provider_type_from_string(req.get_param_value("type"));
|
||||||
@@ -713,7 +576,7 @@ void handlers::handle_post_add_mount(const httplib::Request &req,
|
|||||||
res.status = http_error_codes::ok;
|
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) {
|
httplib::Response &res) {
|
||||||
auto name = req.get_param_value("name");
|
auto name = req.get_param_value("name");
|
||||||
auto prov = provider_type_from_string(req.get_param_value("type"));
|
auto prov = provider_type_from_string(req.get_param_value("type"));
|
||||||
@@ -740,7 +603,7 @@ void handlers::handle_post_mount(const httplib::Request &req,
|
|||||||
res.status = http_error_codes::internal_error;
|
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 {
|
httplib::Response &res) const {
|
||||||
auto name = req.get_param_value("name");
|
auto name = req.get_param_value("name");
|
||||||
auto prov = provider_type_from_string(req.get_param_value("type"));
|
auto prov = provider_type_from_string(req.get_param_value("type"));
|
||||||
@@ -762,7 +625,7 @@ void handlers::handle_put_set_value_by_name(const httplib::Request &req,
|
|||||||
res.status = http_error_codes::ok;
|
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 {
|
httplib::Response &res) const {
|
||||||
auto name = req.get_param_value("name");
|
auto name = req.get_param_value("name");
|
||||||
auto value = req.get_param_value("value");
|
auto value = req.get_param_value("value");
|
||||||
@@ -776,7 +639,7 @@ void handlers::handle_put_setting(const httplib::Request &req,
|
|||||||
res.status = http_error_codes::ok;
|
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 {
|
httplib::Response &res) const {
|
||||||
auto data = nlohmann::json::parse(req.get_param_value("data"));
|
auto data = nlohmann::json::parse(req.get_param_value("data"));
|
||||||
|
|
||||||
@@ -800,7 +663,7 @@ void handlers::handle_put_settings(const httplib::Request &req,
|
|||||||
res.status = http_error_codes::ok;
|
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,
|
std::vector<std::string> args,
|
||||||
bool background) const
|
bool background) const
|
||||||
-> std::vector<std::string> {
|
-> std::vector<std::string> {
|
||||||
@@ -840,10 +703,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(
|
auto &inst_mtx = mtx_lookup_[fmt::format(
|
||||||
"{}-{}", name, app_config::get_provider_name(prov))];
|
"{}-{}", name, app_config::get_provider_name(prov))];
|
||||||
lock.unlock();
|
nonce_lock.unlock();
|
||||||
|
|
||||||
recur_mutex_lock inst_lock(inst_mtx);
|
recur_mutex_lock inst_lock(inst_mtx);
|
||||||
if (background) {
|
if (background) {
|
||||||
@@ -912,7 +775,7 @@ auto handlers::launch_process(provider_type prov, std::string_view name,
|
|||||||
false);
|
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 {
|
const std::string &location) -> bool {
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
if (utils::file::directory{location}.exists()) {
|
if (utils::file::directory{location}.exists()) {
|
||||||
@@ -927,28 +790,33 @@ auto handlers::mount(provider_type prov, std::string_view name,
|
|||||||
config_->set_mount_location(prov, name, location);
|
config_->set_mount_location(prov, name, location);
|
||||||
|
|
||||||
static std::mutex mount_mtx;
|
static std::mutex mount_mtx;
|
||||||
mutex_lock lock(mount_mtx);
|
mutex_lock nonce_lock(mount_mtx);
|
||||||
|
|
||||||
launch_process(prov, name, {location}, true);
|
launch_process(prov, name, {location}, true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void handlers::removed_expired_nonces() {
|
void ui_server::notify_and_unlock(unique_mutex_lock &nonce_lock) {
|
||||||
unique_mutex_lock lock(nonce_mtx_);
|
nonce_notify_.notify_all();
|
||||||
lock.unlock();
|
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) {
|
while (not stop_requested) {
|
||||||
lock.lock();
|
nonce_lock.lock();
|
||||||
auto nonces = nonce_lookup_;
|
auto nonces = nonce_lookup_;
|
||||||
lock.unlock();
|
notify_and_unlock(nonce_lock);
|
||||||
|
|
||||||
for (const auto &[key, value] : nonces) {
|
for (const auto &[key, value] : nonces) {
|
||||||
if (std::chrono::duration_cast<std::chrono::seconds>(
|
if (std::chrono::duration_cast<std::chrono::seconds>(
|
||||||
std::chrono::system_clock::now() - value.creation)
|
std::chrono::system_clock::now() - value.creation)
|
||||||
.count() >= nonce_timeout) {
|
.count() >= nonce_timeout) {
|
||||||
lock.lock();
|
nonce_lock.lock();
|
||||||
nonce_lookup_.erase(key);
|
nonce_lookup_.erase(key);
|
||||||
lock.unlock();
|
notify_and_unlock(nonce_lock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -956,16 +824,16 @@ void handlers::removed_expired_nonces() {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
lock.lock();
|
nonce_lock.lock();
|
||||||
if (stop_requested) {
|
if (stop_requested) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
nonce_notify_.wait_for(lock, std::chrono::seconds(1U));
|
nonce_notify_.wait_for(nonce_lock, std::chrono::seconds(1U));
|
||||||
lock.unlock();
|
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::string_view key, std::string_view value,
|
||||||
std::optional<std::string> data_dir) const {
|
std::optional<std::string> data_dir) const {
|
||||||
std::vector<std::string> args;
|
std::vector<std::string> args;
|
||||||
@@ -978,4 +846,160 @@ void handlers::set_key_value(provider_type prov, std::string_view name,
|
|||||||
args.emplace_back(value);
|
args.emplace_back(value);
|
||||||
launch_process(prov, name, args, false);
|
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
|
} // namespace repertory::ui
|
@@ -27,7 +27,7 @@
|
|||||||
namespace repertory {
|
namespace repertory {
|
||||||
TEST(curl_comm_test, can_create_s3_host_config) {
|
TEST(curl_comm_test, can_create_s3_host_config) {
|
||||||
s3_config config{};
|
s3_config config{};
|
||||||
config.bucket = "repertory";
|
config.bucket = REPERTORY;
|
||||||
config.url = "https://s3.test.com";
|
config.url = "https://s3.test.com";
|
||||||
config.region = "any";
|
config.region = "any";
|
||||||
config.use_path_style = false;
|
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) {
|
TEST(curl_comm_test, can_create_s3_host_config_with_path_style) {
|
||||||
s3_config config{};
|
s3_config config{};
|
||||||
config.bucket = "repertory";
|
config.bucket = REPERTORY;
|
||||||
config.url = "https://s3.test.com";
|
config.url = "https://s3.test.com";
|
||||||
config.region = "any";
|
config.region = "any";
|
||||||
config.use_path_style = true;
|
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) {
|
TEST(curl_comm_test, can_create_s3_host_config_with_region) {
|
||||||
s3_config config{};
|
s3_config config{};
|
||||||
config.bucket = "repertory";
|
config.bucket = REPERTORY;
|
||||||
config.url = "https://s3.test.com";
|
config.url = "https://s3.test.com";
|
||||||
config.region = "any";
|
config.region = "any";
|
||||||
config.use_region_in_url = true;
|
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) {
|
TEST(curl_comm_test, can_create_s3_host_config_with_region_and_path_style) {
|
||||||
s3_config config{};
|
s3_config config{};
|
||||||
config.bucket = "repertory";
|
config.bucket = REPERTORY;
|
||||||
config.url = "https://s3.test.com";
|
config.url = "https://s3.test.com";
|
||||||
config.region = "any";
|
config.region = "any";
|
||||||
config.use_region_in_url = true;
|
config.use_region_in_url = true;
|
||||||
|
Reference in New Issue
Block a user