Compare commits

...

3 Commits

Author SHA1 Message Date
7d441964e9 fixes
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
2025-03-01 07:32:23 -06:00
1d78ee88b8 continue mgmt portal 2025-03-01 07:26:38 -06:00
d54ba8203a continue management portal 2025-03-01 07:13:08 -06:00
7 changed files with 162 additions and 4 deletions

View File

@ -307,6 +307,13 @@ enum class provider_type : std::size_t {
unknown,
};
[[nodiscard]] auto
provider_type_from_string(std::string_view type,
provider_type default_type = provider_type::unknown)
-> provider_type;
[[nodiscard]] auto provider_type_to_string(provider_type type) -> std::string;
#if defined(_WIN32)
struct open_file_data final {
PVOID directory_buffer{nullptr};

View File

@ -726,7 +726,6 @@ auto app_config::default_data_directory(const provider_type &prov)
-> std::string {
return utils::path::combine(app_config::get_root_data_directory(),
{
REPERTORY_DATA_NAME,
app_config::get_provider_name(prov),
});
}

View File

@ -21,6 +21,7 @@
*/
#include "types/repertory.hpp"
#include "app_config.hpp"
#include "types/startup_exception.hpp"
#include "utils/string.hpp"
@ -191,4 +192,34 @@ auto api_error_to_string(const api_error &error) -> const std::string & {
return LOOKUP.at(error);
}
auto provider_type_from_string(std::string_view type,
provider_type default_type) -> provider_type {
auto type_lower = utils::string::to_lower(std::string{type});
if (type_lower == "encrypt") {
return provider_type::encrypt;
}
if (type_lower == "remote") {
return provider_type::remote;
}
if (type_lower == "s3") {
return provider_type::s3;
}
if (type_lower == "sia") {
return provider_type::sia;
}
if (type_lower == "unknown") {
return provider_type::unknown;
}
return default_type;
}
auto provider_type_to_string(provider_type type) -> std::string {
return app_config::get_provider_name(type);
}
} // namespace repertory

View File

@ -56,6 +56,12 @@ private:
private:
console_consumer console;
private:
[[nodiscard]] static auto read_process(provider_type type,
std::string_view name,
std::string_view command)
-> std::vector<std::string>;
};
} // namespace repertory::ui

View File

@ -25,10 +25,11 @@
#include "events/event_system.hpp"
#include "rpc/common.hpp"
#include "types/repertory.hpp"
#include "utils/collection.hpp"
#include "utils/error_utils.hpp"
#include "utils/file.hpp"
#include "utils/path.hpp"
#include <spdlog/fmt/bundled/base.h>
#include "utils/string.hpp"
namespace repertory::ui {
handlers::handlers(mgmt_app_config *config, httplib::Server *server)
@ -71,6 +72,26 @@ handlers::handlers(mgmt_app_config *config, httplib::Server *server)
res.status = http_error_codes::internal_error;
});
server->Get("/api/v1/mount", [](const httplib::Request &req, auto &&res) {
auto prov = provider_type_from_string(req.get_param_value("type"));
auto lines =
handlers::read_process(prov, req.get_param_value("name"), "-dc");
if (lines.at(0U) != "0") {
throw utils::error::create_exception(function_name, {
"command failed",
lines.at(0U),
});
}
lines.erase(lines.begin());
auto result = nlohmann::json::parse(utils::string::join(lines, '\n'));
res.set_content(result.dump(), "application/json");
res.status = http_error_codes::ok;
});
server->Get("/api/v1/mount_list", [](auto && /* req */, auto &&res) {
auto data_dir =
utils::file::directory{app_config::get_root_data_directory()};
@ -102,7 +123,18 @@ handlers::handlers(mgmt_app_config *config, httplib::Server *server)
process_dir("s3");
process_dir("sia");
fmt::println("{}", result.dump());
res.set_content(result.dump(), "application/json");
res.status = http_error_codes::ok;
});
server->Get("/api/v1/mount_status", [](const httplib::Request &req,
auto &&res) {
auto prov = provider_type_from_string(req.get_param_value("type"));
auto lines =
handlers::read_process(prov, req.get_param_value("name"), "-status");
auto result = nlohmann::json::parse(utils::string::join(lines, '\n'));
res.set_content(result.dump(), "application/json");
res.status = http_error_codes::ok;
});
@ -131,4 +163,55 @@ handlers::handlers(mgmt_app_config *config, httplib::Server *server)
}
handlers::~handlers() { event_system::instance().stop(); }
auto handlers::read_process(provider_type type, std::string_view name,
std::string_view command)
-> std::vector<std::string> {
REPERTORY_USES_FUNCTION_NAME();
std::string str_type;
switch (type) {
case provider_type::encrypt:
str_type = "-en";
break;
case provider_type::remote: {
auto parts = utils::string::split(name, '_', false);
str_type = fmt::format("-rm {}:{}", parts[0U], parts[1U]);
} break;
case provider_type::s3:
str_type = fmt::format("-s3 -na {}", name);
break;
case provider_type::sia:
str_type = fmt::format("-na {}", name);
break;
default:
throw utils::error::create_exception(
function_name, {
fmt::format("`{}` is not supported", name),
});
}
auto cmd_line = fmt::format("repertory {} {}", str_type, command);
auto *pipe = popen(cmd_line.c_str(), "r");
if (pipe == nullptr) {
return {};
}
std::string data;
std::array<char, 1024U> buffer{};
while (feof(pipe) == 0) {
while (fgets(buffer.data(), buffer.size(), pipe) != nullptr) {
data += buffer.data();
}
}
pclose(pipe);
return utils::string::split(utils::string::replace(data, "\r", ""), '\n',
false);
}
} // namespace repertory::ui

View File

@ -1,10 +1,34 @@
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http;
import 'package:repertory/types/mount_config.dart';
class Mount with ChangeNotifier {
final MountConfig mountConfig;
Mount(this.mountConfig);
Mount(this.mountConfig) {
_fetch();
}
String get name => mountConfig.name;
String get type => mountConfig.type;
Future<void> _fetch() async {
final response = await http.get(
Uri.parse(
Uri.encodeFull('${Uri.base.origin}/api/v1/mount?name=$name&type=$type'),
),
);
if (response.statusCode == 200) {
mountConfig.updateSettings(jsonDecode(response.body));
notifyListeners();
return;
}
}
void refresh() {
_fetch();
}
}

View File

@ -1,12 +1,20 @@
import 'package:collection/collection.dart';
class MountConfig {
final String _name;
final String _type;
Map<String, dynamic> _settings = {};
MountConfig({required name, required type}) : _name = name, _type = type;
UnmodifiableMapView get items => UnmodifiableMapView(_settings);
String get name => _name;
String get type => _type;
factory MountConfig.fromJson(String type, String name) {
return MountConfig(name: name, type: type);
}
void updateSettings(Map<String, dynamic> settings) {
_settings = settings;
}
}