分离 http依赖
This commit is contained in:
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user