分离 http依赖

This commit is contained in:
2026-08-06 21:33:46 +08:00
parent f060662ffd
commit 14b0b0e3bc
17 changed files with 1486 additions and 514 deletions
+252
View File
@@ -0,0 +1,252 @@
#include "adminive/adapters/boost_pfr.hpp"
#include "adminive/adapters/nlohmann_json.hpp"
#include "adminive/http.hpp"
#include <cassert>
#include <string>
#include <variant>
namespace advanced_test {
using Json = nlohmann::json;
struct Nested_Config {
int count{1};
};
struct Runtime_Model {
Nested_Config nested;
std::string name{"default"};
};
class Runtime_Config {
public:
Runtime_Config() = default;
Runtime_Config(const Runtime_Config&) = delete;
Runtime_Config& operator=(const Runtime_Config&) = delete;
int count() const noexcept {
return count_;
}
const std::string& name() const noexcept {
return name_;
}
void apply(const Runtime_Model& value) {
count_ = value.nested.count;
name_ = value.name;
}
private:
int count_{1};
std::string name_{"default"};
};
struct Base_A {
int alpha{3};
};
struct Base_B {
std::string beta{"base"};
};
struct Inherited_Config : Base_A, Base_B {};
struct Color_Code {
std::string value{"#112233"};
};
struct Control_Config {
Color_Code color;
};
struct Serial_Device {
std::string port{"COM1"};
int baud_rate{115200};
};
struct Network_Device {
std::string host{"127.0.0.1"};
int port{9000};
};
using Device = std::variant<Serial_Device, Network_Device>;
struct Device_Config {
Device device{Serial_Device{}};
};
struct Overview_Status {
adminive::Status_Value<std::string> state{"running", "#16a34a"};
int workers{4};
};
}
namespace adminive {
template <>
struct Boost_Pfr_Name_Adapter<advanced_test::Base_A> {
template <std::size_t Index>
static constexpr std::string_view name() noexcept {
static_assert(Index == 0);
return "alpha";
}
};
template <>
struct Boost_Pfr_Name_Adapter<advanced_test::Base_B> {
template <std::size_t Index>
static constexpr std::string_view name() noexcept {
static_assert(Index == 0);
return "beta";
}
};
template <>
struct Object_Adapter<advanced_test::Runtime_Config> {
using model_type = advanced_test::Runtime_Model;
static model_type snapshot(const advanced_test::Runtime_Config& value) {
model_type result;
result.nested.count = value.count();
result.name = value.name();
return result;
}
static model_type create() {
return {};
}
static void commit(advanced_test::Runtime_Config& target, model_type value) {
target.apply(value);
}
};
template <>
struct Reflection_Adapter<advanced_test::Inherited_Config> : Boost_Pfr_Base_Reflection_Adapter<advanced_test::Inherited_Config, advanced_test::Base_A, advanced_test::Base_B> {};
template <class Json>
struct Value_Adapter<advanced_test::Color_Code, Json> {
using value_type = std::string;
static const std::string& read(const advanced_test::Color_Code& value) noexcept {
return value.value;
}
static void write(advanced_test::Color_Code& target, std::string value) {
target.value = std::move(value);
}
};
template <>
struct Control_Adapter<advanced_test::Color_Code, advanced_test::Json> {
static advanced_test::Json make_control(const advanced_test::Json& field, Control_Context context) {
advanced_test::Json result;
result["type"] = "input-color";
result["name"] = make_field_name(context.prefix, field.at("name").get<std::string>());
result["label"] = field.at("label");
result["clearable"] = true;
return result;
}
static advanced_test::Json make_column(const advanced_test::Json& field) {
return advanced_test::Json{{"type", "tpl"}, {"name", field.at("name")}, {"label", field.at("list_label")}, {"tpl", "<span style=\"color:${color}\">${color}</span>"}};
}
};
template <>
struct Type_Descriptor<advanced_test::Nested_Config> {
static auto get() {
using T = advanced_test::Nested_Config;
return object<T>("nested", "Nested", ADMINIVE_FIELD(T, count).editable()).validator([](const T& value) {
if(value.count < 1) {
throw Field_Validation_Error("count", "count must be positive");
}
});
}
};
template <>
struct Type_Descriptor<advanced_test::Runtime_Model> {
static auto get() {
using T = advanced_test::Runtime_Model;
return object<T>("runtime", "Runtime", ADMINIVE_FIELD(T, nested).editable(), ADMINIVE_FIELD(T, name).editable());
}
};
template <>
struct Type_Descriptor<advanced_test::Inherited_Config> {
static auto get() {
using T = advanced_test::Inherited_Config;
return reflected_object<T>("inherited", "Inherited");
}
};
template <>
struct Type_Descriptor<advanced_test::Control_Config> {
static auto get() {
using T = advanced_test::Control_Config;
return object<T>("control", "Control", ADMINIVE_FIELD(T, color).editable().list_label("颜色"));
}
};
template <>
struct Type_Descriptor<advanced_test::Serial_Device> {
static auto get() {
using T = advanced_test::Serial_Device;
return object<T>("serial", "Serial", ADMINIVE_FIELD(T, port).editable(), ADMINIVE_FIELD(T, baud_rate).editable());
}
};
template <>
struct Type_Descriptor<advanced_test::Network_Device> {
static auto get() {
using T = advanced_test::Network_Device;
return object<T>("network", "Network", ADMINIVE_FIELD(T, host).editable(), ADMINIVE_FIELD(T, port).editable());
}
};
template <>
struct Polymorphic_Adapter<advanced_test::Device, advanced_test::Json> {
static advanced_test::Json descriptor() {
advanced_test::Json variants = advanced_test::Json::array();
variants.push_back(make_polymorphic_variant<advanced_test::Json>("serial", "串口设备", to_descriptor_json<advanced_test::Json, advanced_test::Serial_Device>()));
variants.push_back(make_polymorphic_variant<advanced_test::Json>("network", "网络设备", to_descriptor_json<advanced_test::Json, advanced_test::Network_Device>()));
return make_polymorphic_descriptor<advanced_test::Json>("type", "设备类型", std::move(variants));
}
static advanced_test::Json encode(const advanced_test::Device& value) {
return std::visit([](const auto& device) {
advanced_test::Json result = to_json<advanced_test::Json>(device);
using T = std::remove_cvref_t<decltype(device)>;
result["type"] = std::same_as<T, advanced_test::Serial_Device> ? "serial" : "network";
return result;
}, value);
}
static void decode(advanced_test::Device& target, const advanced_test::Json& value) {
const std::string type = value.at("type").get<std::string>();
if(type == "serial") {
advanced_test::Serial_Device result;
auto update = assign_json<advanced_test::Json>(result, value);
update.field_errors.erase("type");
if(!update.field_errors.empty()) {
throw Json_Assignment_Error(std::move(update));
}
target = std::move(result);
return;
}
if(type == "network") {
advanced_test::Network_Device result;
auto update = assign_json<advanced_test::Json>(result, value);
update.field_errors.erase("type");
if(!update.field_errors.empty()) {
throw Json_Assignment_Error(std::move(update));
}
target = std::move(result);
return;
}
throw Field_Validation_Error("type", "unknown device type");
}
};
template <>
struct Type_Descriptor<advanced_test::Device_Config> {
static auto get() {
using T = advanced_test::Device_Config;
return object<T>("devices", "Devices", ADMINIVE_FIELD(T, device).editable());
}
};
template <>
struct Type_Descriptor<advanced_test::Overview_Status> {
static auto get() {
using T = advanced_test::Overview_Status;
return object<T>("overview", "运行状态", ADMINIVE_FIELD(T, state).label("服务状态"), ADMINIVE_FIELD(T, workers).label("工作线程"));
}
};
}
int main() {
using namespace advanced_test;
Runtime_Config runtime;
adminive::Resource_Service<Runtime_Config, Json> service(runtime, "/config");
const auto invalid = service.update_response(R"({"nested":{"count":0}})");
assert(invalid.status == 422);
assert(invalid.body.at("field_errors").contains("nested.count"));
const auto valid = service.update_response(R"({"nested":{"count":8},"name":"updated"})");
assert(valid.status == 200);
assert(runtime.count() == 8);
assert(runtime.name() == "updated");
const auto inherited = adminive::to_descriptor_json<Json, Inherited_Config>();
assert(inherited.at("fields").at(0).at("name") == "alpha");
assert(inherited.at("fields").at(1).at("name") == "beta");
Control_Config controls;
const auto control_form = adminive::to_amis_form_schema<Json>(controls);
assert(control_form.at("body").at(0).at("type") == "input-color");
Device_Config devices;
const auto device_form = adminive::to_amis_form_schema<Json>(devices);
assert(device_form.at("body").at(0).at("type") == "fieldset");
assert(device_form.at("body").at(0).at("body").at(0).at("type") == "select");
const auto status_descriptor = adminive::to_status_descriptor_json<Json, Overview_Status>();
const auto status_service = adminive::make_amis_status_service<Json>(status_descriptor, "/status", 1000);
assert(status_service.at("body").at("title") == "运行状态");
assert(status_service.at("body").at("body").at("body").size() == 2);
return 0;
}