Files
Adminive/backend/src/example.hpp
T
2026-08-06 21:33:46 +08:00

238 lines
10 KiB
C++

#pragma once
#include "adminive/adminive.hpp"
#include "adminive/adapters/magic_enum.hpp"
#include "adminive/adapters/nlohmann_json.hpp"
#include "adminive/adapters/httplib.hpp"
#include <chrono>
#include <cstdint>
#include <ctime>
#include <iomanip>
#include <sstream>
#include <stdexcept>
#include <string>
#include <string_view>
namespace adminive::example {
using Json = nlohmann::json;
template <class T>
using Http_Resource = adminive::Http_Resource<T, Json>;
template <class T>
using Http_Collection_Resource = adminive::Http_Collection_Resource<T, Json>;
inline std::string format_utc_time(std::chrono::system_clock::time_point value) {
const std::time_t raw_time = std::chrono::system_clock::to_time_t(value);
std::tm utc_time{};
#ifdef _WIN32
gmtime_s(&utc_time, &raw_time);
#else
gmtime_r(&raw_time, &utc_time);
#endif
std::ostringstream stream;
stream << std::put_time(&utc_time, "%Y-%m-%dT%H:%M:%SZ");
return stream.str();
}
enum class Radio_Mode {
receive,
transmit,
duplex,
maintenance
};
enum class Radio_Operating_State {
starting,
running,
degraded,
stopped
};
enum class Log_Level {
trace,
debug,
info,
warning,
error
};
enum class Alert_Channel {
dashboard,
email,
webhook
};
struct Server_Status {
std::string service_state{"running"};
std::string server_time;
std::uint64_t uptime_seconds{};
std::uint64_t poll_sequence{};
std::uint64_t radio_state_count{};
int listen_port{};
};
struct Radio_Item_Status {
Status_Value<Radio_Operating_State> operating_state;
Status_Value<std::uint64_t> refresh_sequence;
Status_Value<std::string> refresh_time;
};
struct Endpoint_Config {
bool enabled{true};
std::string host{"127.0.0.1"};
Range_Value<int, 1, 65535> port{9000};
};
struct Appearance_Config {
std::string panel_title{"Radio Control"};
std::string effective_date{"2026-08-06"};
std::string accent_color{"#2563eb"};
};
struct Radio_Service_Config {
std::string profile_name{"Primary Radio Profile"};
Radio_Mode mode{Radio_Mode::receive};
Range_Value<int, 1, 64> worker_count{4};
double receive_gain{1.25};
Endpoint_Config primary_endpoint{};
Endpoint_Config backup_endpoint{true, "127.0.0.2", Range_Value<int, 1, 65535>{9001}};
Appearance_Config appearance{};
};
struct Alert_Config {
bool enabled{true};
std::string rule_name{"Radio Health Alert"};
Alert_Channel channel{Alert_Channel::dashboard};
Log_Level minimum_level{Log_Level::warning};
Range_Value<int, 1, 1440> repeat_minutes{10};
std::string effective_date{"2026-08-06"};
std::string highlight_color{"#d97706"};
Endpoint_Config webhook_endpoint{true, "127.0.0.1", Range_Value<int, 1, 65535>{9100}};
};
struct Radio_State {
struct Even_Validator {
static constexpr int multiple_of = 2;
static constexpr std::string_view message = "buffer_count must be even";
void operator()(const int& value) const {
if(value % 2 != 0) {
throw std::invalid_argument("buffer_count must be even");
}
}
};
struct Watermark_Validator {
void operator()(const Radio_State& value) const {
if(value.low_watermark > value.high_watermark) {
throw std::invalid_argument("low_watermark must not exceed high_watermark");
}
}
};
Radio_Mode mode{Radio_Mode::receive};
Range_Value<int, 1, 65535> port{9999};
Validated_Value<int, Even_Validator> buffer_count{2};
int low_watermark{};
int high_watermark{};
Radio_Item_Status status() {
const auto now = std::chrono::system_clock::now();
const auto seconds = std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch()).count();
const auto state_index = (static_cast<std::uint64_t>(seconds / 4) + static_cast<std::uint64_t>(port.value())) % 4;
Radio_Operating_State state{};
std::string color;
switch(state_index) {
case 0:
state = Radio_Operating_State::starting;
color = "#2563eb";
break;
case 1:
state = Radio_Operating_State::running;
color = "#16a34a";
break;
case 2:
state = Radio_Operating_State::degraded;
color = "#d97706";
break;
default:
state = Radio_Operating_State::stopped;
color = "#dc2626";
break;
}
++status_sequence_;
return Radio_Item_Status{status_value(state, std::move(color)), status_value(status_sequence_, "#475569"), status_value(format_utc_time(now), "#475569")};
}
private:
std::uint64_t status_sequence_{};
};
}
namespace adminive {
template <>
struct Type_Descriptor<example::Server_Status> {
static auto get() {
using T = example::Server_Status;
return object<T>("server_status", ADMINIVE_FIELD(T, service_state), ADMINIVE_FIELD(T, server_time), ADMINIVE_FIELD(T, uptime_seconds), ADMINIVE_FIELD(T, poll_sequence), ADMINIVE_FIELD(T, radio_state_count), ADMINIVE_FIELD(T, listen_port)).label("Server Status");
}
};
template <>
struct Type_Descriptor<example::Radio_Item_Status> {
static auto get() {
using T = example::Radio_Item_Status;
return object<T>("radio_item_status", ADMINIVE_FIELD_LABEL(T, operating_state, "State"), ADMINIVE_FIELD_LABEL(T, refresh_sequence, "Refresh Sequence"), ADMINIVE_FIELD_LABEL(T, refresh_time, "Refresh Time")).label("Runtime Status");
}
};
template <>
struct Type_Descriptor<example::Endpoint_Config> {
static auto get() {
using T = example::Endpoint_Config;
return object<T>(
"endpoint_config",
ADMINIVE_FIELD_LABEL(T, enabled, "Enable Endpoint").editable().creatable().description("Controls whether this endpoint participates in the current configuration"),
ADMINIVE_FIELD_LABEL(T, host, "Host Address").editable().creatable().required().description("String input example"),
ADMINIVE_FIELD_LABEL(T, port, "Port").editable().creatable().required().description("Integer input example")
).label("Endpoint");
}
};
template <>
struct Type_Descriptor<example::Appearance_Config> {
static auto get() {
using T = example::Appearance_Config;
return object<T>(
"appearance_config",
ADMINIVE_FIELD_LABEL(T, panel_title, "Panel Title").editable().creatable().required().description("String input example"),
ADMINIVE_FIELD_LABEL(T, effective_date, "Effective Date").editable().creatable().required().widget("input-date").description("Date selector example"),
ADMINIVE_FIELD_LABEL(T, accent_color, "Accent Color").editable().creatable().required().widget("input-color").description("Color selector example")
).label("Appearance");
}
};
template <>
struct Type_Descriptor<example::Radio_Service_Config> {
static auto get() {
using T = example::Radio_Service_Config;
return object<T>(
"radio_service_config",
ADMINIVE_FIELD_LABEL(T, profile_name, "Profile Name").editable().required().description("Editable string configuration"),
ADMINIVE_FIELD_LABEL(T, mode, "Operating Mode").editable().required().description("Enum options are generated by magic_enum"),
ADMINIVE_FIELD_LABEL(T, worker_count, "Worker Count").editable().required().description("Integer number input"),
ADMINIVE_FIELD_LABEL(T, receive_gain, "Receive Gain").editable().required().description("Floating-point number input"),
ADMINIVE_FIELD_LABEL(T, primary_endpoint, "Primary Endpoint").editable().description("First child configuration group"),
ADMINIVE_FIELD_LABEL(T, backup_endpoint, "Backup Endpoint").editable().visible_on("${mode == 'duplex'}").description("Displayed only when Operating Mode is duplex"),
ADMINIVE_FIELD_LABEL(T, appearance, "Appearance").editable().description("Nested date and color controls")
).label("Radio Service Configuration");
}
};
template <>
struct Type_Descriptor<example::Alert_Config> {
static auto get() {
using T = example::Alert_Config;
return object<T>(
"alert_config",
ADMINIVE_FIELD_LABEL(T, enabled, "Enable Alerts").editable(),
ADMINIVE_FIELD_LABEL(T, rule_name, "Rule Name").editable().required(),
ADMINIVE_FIELD_LABEL(T, channel, "Delivery Channel").editable().required().description("Enum options are generated by magic_enum"),
ADMINIVE_FIELD_LABEL(T, minimum_level, "Minimum Log Level").editable().required().description("Second enum example"),
ADMINIVE_FIELD_LABEL(T, repeat_minutes, "Repeat Interval Minutes").editable().required(),
ADMINIVE_FIELD_LABEL(T, effective_date, "Effective Date").editable().required().widget("input-date"),
ADMINIVE_FIELD_LABEL(T, highlight_color, "Highlight Color").editable().required().widget("input-color"),
ADMINIVE_FIELD_LABEL(T, webhook_endpoint, "Webhook Endpoint").editable().visible_on("${enabled && channel == 'webhook'}").description("Displayed only when alerts are enabled and channel is webhook")
).label("Alert Configuration");
}
};
template <>
struct Type_Descriptor<example::Radio_State> {
static auto get() {
using T = example::Radio_State;
return object<T>(
"radio_state",
ADMINIVE_FIELD_LABEL(T, mode, "Operating Mode").creatable().editable().required().list_label("Mode").order(5).sortable().description("Enum list column generated through magic_enum"),
ADMINIVE_FIELD(T, port).creatable().editable().required().description("Listening port").list_label("Listen Port").order(20).sortable(),
ADMINIVE_FIELD(T, buffer_count).creatable().editable().required().list_label("Buffers").order(10).sortable(),
ADMINIVE_FIELD(T, low_watermark).creatable().editable().order(30),
ADMINIVE_FIELD(T, high_watermark).creatable().editable().order(40)
).label("Radio State").validator(T::Watermark_Validator{});
}
};
}