Compare commits
12 Commits
e3d036fcb8
...
0e8e56ad90
Author | SHA1 | Date | |
---|---|---|---|
0e8e56ad90 | |||
e53acf799a | |||
c2eaa92f4a | |||
13eab49207 | |||
616dca89ca | |||
9626f383d3 | |||
a262a79eb2 | |||
f9ec02bf3f | |||
e6793f0d6c | |||
0d972b0b75 | |||
60f0e3dbc1 | |||
630c3463d8 |
@ -12,6 +12,7 @@
|
||||
### Changes from v2.0.4-rc
|
||||
|
||||
* Continue documentation updates
|
||||
* Prevent overlapping `repertory` `ApiPort`'s
|
||||
* Removed passwords and secret key values from API calls
|
||||
* Renamed setting `ApiAuth` to `ApiPassword`
|
||||
* Require `--name,-na` option for encryption provider
|
||||
|
@ -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;
|
||||
|
@ -67,7 +67,7 @@ app_config::app_config(const provider_type &prov,
|
||||
std::string_view data_directory)
|
||||
: prov_(prov),
|
||||
api_password_(utils::generate_random_string(default_api_password_size)),
|
||||
api_port_(default_rpc_port(prov)),
|
||||
api_port_(default_rpc_port()),
|
||||
api_user_(std::string{REPERTORY}),
|
||||
config_changed_(false),
|
||||
download_timeout_secs_(default_download_timeout_secs),
|
||||
@ -743,17 +743,7 @@ 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::default_rpc_port() -> std::uint16_t { return 10000U; }
|
||||
|
||||
auto app_config::get_api_password() const -> std::string {
|
||||
return api_password_;
|
||||
@ -943,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));
|
||||
}
|
||||
|
@ -143,8 +143,17 @@ 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]() {
|
||||
#ifdef _WIN32
|
||||
server_->set_socket_options([](auto &&sock) {
|
||||
int enable = 1;
|
||||
setsockopt(sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
|
||||
reinterpret_cast<const char *>(&enable), sizeof(enable));
|
||||
});
|
||||
#endif // _WIN32
|
||||
|
||||
server_->listen("127.0.0.1", config_.get_api_port());
|
||||
});
|
||||
event_system::instance().raise<service_start_end>(function_name, "server");
|
||||
}
|
||||
|
||||
|
@ -29,8 +29,7 @@
|
||||
#include "types/repertory.hpp"
|
||||
#include "utils/cli_utils.hpp"
|
||||
#include "utils/com_init_wrapper.hpp"
|
||||
#include "utils/file_utils.hpp"
|
||||
#include "utils/string.hpp"
|
||||
#include "utils/file.hpp"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include "drives/winfsp/remotewinfsp/remote_client.hpp"
|
||||
@ -57,130 +56,141 @@ namespace repertory::cli::actions {
|
||||
mount(std::vector<const char *> args, std::string data_directory,
|
||||
int &mount_result, provider_type prov, const std::string &remote_host,
|
||||
std::uint16_t remote_port, const std::string &unique_id) -> exit_code {
|
||||
auto ret = exit_code::success;
|
||||
|
||||
lock_data lock(prov, unique_id);
|
||||
const auto res = lock.grab_lock();
|
||||
if (res == lock_result::locked) {
|
||||
ret = exit_code::mount_active;
|
||||
auto lock_result = lock.grab_lock();
|
||||
if (lock_result == lock_result::locked) {
|
||||
std::cerr << app_config::get_provider_display_name(prov)
|
||||
<< " mount is already active" << std::endl;
|
||||
} else if (res == lock_result::success) {
|
||||
const auto generate_config = utils::cli::has_option(
|
||||
args, utils::cli::options::generate_config_option);
|
||||
if (generate_config) {
|
||||
app_config config(prov, data_directory);
|
||||
if (prov == provider_type::remote) {
|
||||
auto cfg = config.get_remote_config();
|
||||
cfg.host_name_or_ip = remote_host;
|
||||
cfg.api_port = remote_port;
|
||||
config.set_remote_config(cfg);
|
||||
} else if (prov == provider_type::sia &&
|
||||
config.get_sia_config().bucket.empty()) {
|
||||
[[maybe_unused]] auto bucket =
|
||||
config.set_value_by_name("SiaConfig.Bucket", unique_id);
|
||||
}
|
||||
|
||||
std::cout << "Generated " << app_config::get_provider_display_name(prov)
|
||||
<< " Configuration" << std::endl;
|
||||
std::cout << config.get_config_file_path() << std::endl;
|
||||
ret = utils::file::file(config.get_config_file_path()).exists()
|
||||
? exit_code::success
|
||||
: exit_code::file_creation_failed;
|
||||
} else {
|
||||
#if defined(_WIN32)
|
||||
if (utils::cli::has_option(args, utils::cli::options::hidden_option)) {
|
||||
::ShowWindow(::GetConsoleWindow(), SW_HIDE);
|
||||
}
|
||||
#endif // defined(_WIN32)
|
||||
auto drive_args =
|
||||
utils::cli::parse_drive_options(args, prov, data_directory);
|
||||
app_config config(prov, data_directory);
|
||||
#if defined(_WIN32)
|
||||
if (config.get_enable_mount_manager() &&
|
||||
not utils::is_process_elevated()) {
|
||||
utils::com_init_wrapper cw;
|
||||
if (not lock.set_mount_state(true, "elevating", -1)) {
|
||||
std::cerr << "failed to set mount state" << std::endl;
|
||||
}
|
||||
lock.release();
|
||||
|
||||
mount_result = utils::run_process_elevated(args);
|
||||
lock_data lock2(prov, unique_id);
|
||||
if (lock2.grab_lock() == lock_result::success) {
|
||||
if (not lock2.set_mount_state(false, "", -1)) {
|
||||
std::cerr << "failed to set mount state" << std::endl;
|
||||
}
|
||||
lock2.release();
|
||||
}
|
||||
|
||||
return exit_code::mount_result;
|
||||
}
|
||||
#endif // defined(_WIN32)
|
||||
std::cout << "Initializing "
|
||||
<< app_config::get_provider_display_name(prov)
|
||||
<< (unique_id.empty() ? ""
|
||||
: (prov == provider_type::remote)
|
||||
? " [" + remote_host + ':' +
|
||||
std::to_string(remote_port) + ']'
|
||||
: " [" + unique_id + ']')
|
||||
<< " Drive" << std::endl;
|
||||
if (prov == provider_type::remote) {
|
||||
std::uint16_t port{0U};
|
||||
if (utils::get_next_available_port(config.get_api_port(), port)) {
|
||||
auto cfg = config.get_remote_config();
|
||||
cfg.host_name_or_ip = remote_host;
|
||||
cfg.api_port = remote_port;
|
||||
config.set_remote_config(cfg);
|
||||
config.set_api_port(port);
|
||||
|
||||
try {
|
||||
remote_drive drive(
|
||||
config,
|
||||
[&config]() -> std::unique_ptr<remote_instance> {
|
||||
return std::unique_ptr<remote_instance>(
|
||||
new remote_client(config));
|
||||
},
|
||||
lock);
|
||||
if (not lock.set_mount_state(true, "", -1)) {
|
||||
std::cerr << "failed to set mount state" << std::endl;
|
||||
}
|
||||
mount_result = drive.mount(drive_args);
|
||||
ret = exit_code::mount_result;
|
||||
} catch (const std::exception &e) {
|
||||
std::cerr << "FATAL: " << e.what() << std::endl;
|
||||
ret = exit_code::startup_exception;
|
||||
}
|
||||
} else {
|
||||
std::cerr << "FATAL: Unable to get available port" << std::endl;
|
||||
ret = exit_code::startup_exception;
|
||||
}
|
||||
} else {
|
||||
if (prov == provider_type::sia &&
|
||||
config.get_sia_config().bucket.empty()) {
|
||||
[[maybe_unused]] auto bucket =
|
||||
config.set_value_by_name("SiaConfig.Bucket", unique_id);
|
||||
}
|
||||
|
||||
try {
|
||||
auto provider = create_provider(prov, config);
|
||||
repertory_drive drive(config, lock, *provider);
|
||||
if (not lock.set_mount_state(true, "", -1)) {
|
||||
std::cerr << "failed to set mount state" << std::endl;
|
||||
}
|
||||
mount_result = drive.mount(drive_args);
|
||||
ret = exit_code::mount_result;
|
||||
} catch (const std::exception &e) {
|
||||
std::cerr << "FATAL: " << e.what() << std::endl;
|
||||
ret = exit_code::startup_exception;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ret = exit_code::lock_failed;
|
||||
return exit_code::mount_active;
|
||||
}
|
||||
|
||||
return ret;
|
||||
if (lock_result != lock_result::success) {
|
||||
std::cerr << "FATAL: Unable to get provider lock" << std::endl;
|
||||
return exit_code::lock_failed;
|
||||
}
|
||||
|
||||
if (utils::cli::has_option(args,
|
||||
utils::cli::options::generate_config_option)) {
|
||||
app_config config(prov, data_directory);
|
||||
if (prov == provider_type::remote) {
|
||||
auto remote_config = config.get_remote_config();
|
||||
remote_config.host_name_or_ip = remote_host;
|
||||
remote_config.api_port = remote_port;
|
||||
config.set_remote_config(remote_config);
|
||||
} else if (prov == provider_type::sia &&
|
||||
config.get_sia_config().bucket.empty()) {
|
||||
[[maybe_unused]] auto bucket =
|
||||
config.set_value_by_name("SiaConfig.Bucket", unique_id);
|
||||
}
|
||||
|
||||
std::cout << "Generated " << app_config::get_provider_display_name(prov)
|
||||
<< " Configuration" << std::endl;
|
||||
std::cout << config.get_config_file_path() << std::endl;
|
||||
return utils::file::file(config.get_config_file_path()).exists()
|
||||
? exit_code::success
|
||||
: exit_code::file_creation_failed;
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
if (utils::cli::has_option(args, utils::cli::options::hidden_option)) {
|
||||
::ShowWindow(::GetConsoleWindow(), SW_HIDE);
|
||||
}
|
||||
#endif // defined(_WIN32)
|
||||
|
||||
lock_data global_lock(provider_type::unknown, "global");
|
||||
lock_result = global_lock.grab_lock(100U);
|
||||
if (lock_result != lock_result::success) {
|
||||
std::cerr << "FATAL: Unable to get global lock" << std::endl;
|
||||
return exit_code::lock_failed;
|
||||
}
|
||||
|
||||
auto drive_args = utils::cli::parse_drive_options(args, prov, data_directory);
|
||||
app_config config(prov, data_directory);
|
||||
{
|
||||
std::uint16_t port{};
|
||||
if (not utils::get_next_available_port(config.get_api_port(), port)) {
|
||||
std::cerr << "FATAL: Unable to get available port" << std::endl;
|
||||
return exit_code::startup_exception;
|
||||
}
|
||||
config.set_api_port(port);
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
if (config.get_enable_mount_manager() && not utils::is_process_elevated()) {
|
||||
utils::com_init_wrapper wrapper;
|
||||
if (not lock.set_mount_state(true, "elevating", -1)) {
|
||||
std::cerr << "failed to set mount state" << std::endl;
|
||||
}
|
||||
lock.release();
|
||||
global_lock.release();
|
||||
|
||||
mount_result = utils::run_process_elevated(args);
|
||||
lock_data prov_lock(prov, unique_id);
|
||||
if (prov_lock.grab_lock() == lock_result::success) {
|
||||
if (not prov_lock.set_mount_state(false, "", -1)) {
|
||||
std::cerr << "failed to set mount state" << std::endl;
|
||||
}
|
||||
prov_lock.release();
|
||||
}
|
||||
|
||||
return exit_code::mount_result;
|
||||
}
|
||||
#endif // defined(_WIN32)
|
||||
|
||||
std::cout << "Initializing " << app_config::get_provider_display_name(prov)
|
||||
<< (unique_id.empty() ? ""
|
||||
: (prov == provider_type::remote)
|
||||
? " [" + remote_host + ':' + std::to_string(remote_port) +
|
||||
']'
|
||||
: " [" + unique_id + ']')
|
||||
<< " Drive" << std::endl;
|
||||
if (prov == provider_type::remote) {
|
||||
try {
|
||||
auto remote_cfg = config.get_remote_config();
|
||||
remote_cfg.host_name_or_ip = remote_host;
|
||||
remote_cfg.api_port = remote_port;
|
||||
config.set_remote_config(remote_cfg);
|
||||
|
||||
remote_drive drive(
|
||||
config,
|
||||
[&config]() -> std::unique_ptr<remote_instance> {
|
||||
return std::unique_ptr<remote_instance>(new remote_client(config));
|
||||
},
|
||||
lock);
|
||||
if (not lock.set_mount_state(true, "", -1)) {
|
||||
std::cerr << "failed to set mount state" << std::endl;
|
||||
}
|
||||
|
||||
global_lock.release();
|
||||
mount_result = drive.mount(drive_args);
|
||||
return exit_code::mount_result;
|
||||
} catch (const std::exception &e) {
|
||||
std::cerr << "FATAL: " << e.what() << std::endl;
|
||||
}
|
||||
|
||||
return exit_code::startup_exception;
|
||||
}
|
||||
|
||||
try {
|
||||
if (prov == provider_type::sia && config.get_sia_config().bucket.empty()) {
|
||||
[[maybe_unused]] auto bucket =
|
||||
config.set_value_by_name("SiaConfig.Bucket", unique_id);
|
||||
}
|
||||
|
||||
auto provider = create_provider(prov, config);
|
||||
repertory_drive drive(config, lock, *provider);
|
||||
if (not lock.set_mount_state(true, "", -1)) {
|
||||
std::cerr << "failed to set mount state" << std::endl;
|
||||
}
|
||||
|
||||
global_lock.release();
|
||||
mount_result = drive.mount(drive_args);
|
||||
return exit_code::mount_result;
|
||||
} catch (const std::exception &e) {
|
||||
std::cerr << "FATAL: " << e.what() << std::endl;
|
||||
}
|
||||
|
||||
return exit_code::startup_exception;
|
||||
}
|
||||
} // namespace repertory::cli::actions
|
||||
|
||||
|
@ -109,6 +109,14 @@ handlers::handlers(mgmt_app_config *config, httplib::Server *server)
|
||||
server_(server) {
|
||||
REPERTORY_USES_FUNCTION_NAME();
|
||||
|
||||
#ifdef _WIN32
|
||||
server_->set_socket_options([](auto &&sock) {
|
||||
int enable = 1;
|
||||
setsockopt(sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
|
||||
reinterpret_cast<const char *>(&enable), sizeof(enable));
|
||||
});
|
||||
#endif // _WIN32
|
||||
|
||||
server_->set_pre_routing_handler(
|
||||
[this](const httplib::Request &req,
|
||||
auto &&res) -> httplib::Server::HandlerResponse {
|
||||
@ -505,8 +513,13 @@ void handlers::handle_post_mount(const httplib::Request &req,
|
||||
return;
|
||||
}
|
||||
|
||||
static std::mutex mount_mtx;
|
||||
mutex_lock lock(mount_mtx);
|
||||
|
||||
launch_process(prov, name, {location}, true);
|
||||
config_->set_mount_location(prov, name, location);
|
||||
|
||||
launch_process(prov, name, {"-status"});
|
||||
}
|
||||
|
||||
res.status = http_error_codes::ok;
|
||||
|
@ -128,7 +128,7 @@ std::atomic<std::uint64_t> app_config_test::idx{0U};
|
||||
|
||||
static void defaults_tests(const json &json_data, provider_type prov) {
|
||||
json json_defaults = {
|
||||
{JSON_API_PORT, app_config::default_rpc_port(prov)},
|
||||
{JSON_API_PORT, app_config::default_rpc_port()},
|
||||
{JSON_API_USER, std::string{REPERTORY}},
|
||||
{JSON_DOWNLOAD_TIMEOUT_SECS, default_download_timeout_secs},
|
||||
{JSON_DATABASE_TYPE, database_type::rocksdb},
|
||||
|
@ -25,8 +25,8 @@
|
||||
#include "utils/string.hpp"
|
||||
|
||||
namespace repertory::utils {
|
||||
auto compare_version_strings(std::string version1,
|
||||
std::string version2) -> std::int32_t {
|
||||
auto compare_version_strings(std::string version1, std::string version2)
|
||||
-> std::int32_t {
|
||||
|
||||
if (utils::string::contains(version1, "-")) {
|
||||
version1 = utils::string::split(version1, '-', true)[0U];
|
||||
@ -131,23 +131,46 @@ auto get_next_available_port(std::uint16_t first_port,
|
||||
using ip::tcp;
|
||||
|
||||
boost::system::error_code error_code{};
|
||||
while (first_port != 0U) {
|
||||
io_context ctx{};
|
||||
tcp::acceptor acceptor(ctx);
|
||||
acceptor.open(tcp::v4(), error_code) ||
|
||||
acceptor.bind({tcp::v4(), first_port}, error_code);
|
||||
if (not error_code) {
|
||||
break;
|
||||
|
||||
std::uint32_t check_port{first_port};
|
||||
while (check_port <= 65535U) {
|
||||
{
|
||||
io_context ctx{};
|
||||
tcp::socket socket(ctx);
|
||||
socket.connect(
|
||||
{
|
||||
tcp::endpoint(ip::address_v4::loopback(),
|
||||
static_cast<std::uint16_t>(check_port)),
|
||||
},
|
||||
error_code);
|
||||
if (not error_code) {
|
||||
++check_port;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
++first_port;
|
||||
{
|
||||
io_context ctx{};
|
||||
tcp::acceptor acceptor(ctx);
|
||||
acceptor.open(tcp::v4(), error_code);
|
||||
if (error_code) {
|
||||
++check_port;
|
||||
continue;
|
||||
}
|
||||
|
||||
acceptor.bind({tcp::v4(), static_cast<std::uint16_t>(check_port)},
|
||||
error_code);
|
||||
if (error_code) {
|
||||
++check_port;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
available_port = static_cast<std::uint16_t>(check_port);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (not error_code) {
|
||||
available_port = first_port;
|
||||
}
|
||||
|
||||
return not error_code;
|
||||
return false;
|
||||
}
|
||||
#endif // defined(PROJECT_ENABLE_BOOST)
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
@ -111,10 +112,19 @@ class MountList with ChangeNotifier {
|
||||
Future<bool> add(
|
||||
String type,
|
||||
String name,
|
||||
Map<String, dynamic> mountConfig,
|
||||
Map<String, dynamic> settings,
|
||||
) async {
|
||||
var ret = false;
|
||||
|
||||
var apiPort = settings['ApiPort'] ?? 10000;
|
||||
for (var mount in _mountList) {
|
||||
var port = mount.mountConfig.settings['ApiPort'] as int?;
|
||||
if (port != null) {
|
||||
apiPort = max(apiPort, port + 1);
|
||||
}
|
||||
}
|
||||
settings["ApiPort"] = apiPort;
|
||||
|
||||
displayError() {
|
||||
if (constants.navigatorKey.currentContext == null) {
|
||||
return;
|
||||
@ -129,7 +139,7 @@ class MountList with ChangeNotifier {
|
||||
try {
|
||||
final auth = await _auth.createAuth();
|
||||
final map = await convertAllToString(
|
||||
jsonDecode(jsonEncode(mountConfig)),
|
||||
jsonDecode(jsonEncode(settings)),
|
||||
_auth.key,
|
||||
);
|
||||
final response = await http.post(
|
||||
|
Loading…
x
Reference in New Issue
Block a user