Files
Adminive/backend/src/server_app.cpp
T
2026-08-07 00:01:16 +08:00

77 lines
4.3 KiB
C++

#include "server_app.hpp"
#include <iostream>
namespace adminive::example {
namespace {
Radio_State make_radio_state(Radio_Mode mode, int port, int buffer_count, int low_watermark, int high_watermark) {
Radio_State result;
result.mode = mode;
result.port = port;
result.buffer_count = buffer_count;
result.low_watermark = low_watermark;
result.high_watermark = high_watermark;
return result;
}
}
Server_App::Server_App(int port, std::filesystem::path frontend_dist, std::filesystem::path config_file) : port_(port), frontend_dist_(std::move(frontend_dist)), config_store_(std::move(config_file)), state_resource_("/admin/radio_states", make_radio_states()), service_config_resource_(config_store_.data().radio_service, "/admin/config/radio", adminive::make_resource_transaction<Radio_Service_Config>([this](const Radio_Service_Config& value, const Request_Context&) {
config_store_.write_radio_service_candidate(value);
}), &config_store_.mutex()), alert_config_resource_(config_store_.data().alerts, "/admin/config/alerts", adminive::make_resource_transaction<Alert_Config>([this](const Alert_Config& value, const Request_Context&) {
config_store_.write_alerts_candidate(value);
}), &config_store_.mutex()), device_tables_(config_store_) {
state_resource_.register_overview_status<Server_Status>("/admin/status", 2000);
state_resource_.register_status<&Radio_State::status>(2000);
bind_routes();
}
int Server_App::run() {
if(!server_.set_mount_point("/", frontend_dist_.string())) {
std::cerr << "frontend build directory does not exist: " << frontend_dist_.string() << '\n';
std::cerr << "run npm run build from the project root before starting the backend\n";
return 3;
}
std::cout << "Adminive server listening on http://127.0.0.1:" << port_ << '\n';
std::cout << "Serving frontend from " << frontend_dist_.string() << '\n';
std::cout << "Configuration file " << config_store_.path().string() << '\n';
std::cout << std::flush;
if(!server_.listen("0.0.0.0", port_)) {
std::cerr << "failed to start server\n";
return 1;
}
return 0;
}
Json Server_App::amis_schema() const {
Json tabs = Json::array();
const Json states_schema = state_resource_.amis_schema();
tabs.push_back(Json{{"title", "无线电状态"}, {"body", states_schema.at("body")}});
tabs.push_back(Json{{"title", "无线电服务配置"}, {"body", service_config_resource_.amis_schema()}});
tabs.push_back(Json{{"title", "告警配置"}, {"body", alert_config_resource_.amis_schema()}});
tabs.push_back(Json{{"title", "多类型设备"}, {"body", device_tables_.amis_schema()}});
return Json{{"type", "page"}, {"title", "Adminive 完整示例"}, {"subTitle", "列表中文映射、后端排序、拖拽顺序、多态类型表格和持久化配置均由后端定义"}, {"body", Json{{"type", "tabs"}, {"tabs", std::move(tabs)}}}};
}
std::vector<Radio_State> Server_App::make_radio_states() {
return {
make_radio_state(Radio_Mode::receive, 10001, 2, 16, 64),
make_radio_state(Radio_Mode::transmit, 10002, 4, 32, 128),
make_radio_state(Radio_Mode::duplex, 10003, 8, 64, 256)
};
}
void Server_App::bind_routes() {
state_resource_.bind(server_);
service_config_resource_.bind(server_);
alert_config_resource_.bind(server_);
device_tables_.bind(server_);
server_.Get("/admin/amis", [this](const httplib::Request&, httplib::Response& response) {
write_http_json(response, Json{{"status", 0}, {"msg", ""}, {"data", amis_schema()}});
});
server_.Get("/admin/status", [this](const httplib::Request&, httplib::Response& response) {
const auto now = std::chrono::system_clock::now();
const auto uptime = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::steady_clock::now() - started_at_).count();
Server_Status status;
status.server_time = format_utc_time(now);
status.uptime_seconds = static_cast<std::uint64_t>(uptime);
status.poll_sequence = poll_sequence_.fetch_add(1, std::memory_order_relaxed) + 1;
status.radio_state_count = state_resource_.size();
status.listen_port = port_;
write_http_json(response, Json{{"status", 0}, {"msg", ""}, {"data", to_status_json<Json>(status)}});
});
}
}