OrangePi3588Media/include/utils/config_schema.h

239 lines
7.3 KiB
C++

#pragma once
#include <string>
#include <unordered_set>
#include "utils/simple_json.h"
namespace rk3588 {
inline bool IsStringNonEmpty(const SimpleJson* v) {
return v && v->IsString() && !v->AsString("").empty();
}
inline bool IsDropStrategy(const std::string& s) {
return s == "drop_oldest" || s == "drop_newest" || s == "block";
}
inline bool ValidateQueueCfg(const SimpleJson& q, std::string& err) {
if (!q.IsObject()) {
err = "queue must be object";
return false;
}
if (const SimpleJson* s = q.Find("size")) {
if (!s->IsNumber() || s->AsInt(0) <= 0) {
err = "queue.size must be positive number";
return false;
}
}
std::string policy;
if (const SimpleJson* p = q.Find("policy")) {
if (!p->IsString()) {
err = "queue.policy must be string";
return false;
}
policy = p->AsString("");
}
if (policy.empty()) {
if (const SimpleJson* p = q.Find("strategy")) {
if (!p->IsString()) {
err = "queue.strategy must be string";
return false;
}
policy = p->AsString("");
}
}
if (!policy.empty() && !IsDropStrategy(policy)) {
err = "queue policy/strategy must be one of: drop_oldest, drop_newest, block";
return false;
}
return true;
}
inline bool ValidateNodeCfg(const SimpleJson& node, std::string& err) {
if (!node.IsObject()) {
err = "node entry must be object";
return false;
}
if (!IsStringNonEmpty(node.Find("id"))) {
err = "node.id must be non-empty string";
return false;
}
if (!IsStringNonEmpty(node.Find("type"))) {
err = "node.type must be non-empty string";
return false;
}
if (const SimpleJson* en = node.Find("enable")) {
if (!en->IsBool()) {
err = "node.enable must be bool";
return false;
}
}
if (const SimpleJson* role = node.Find("role")) {
if (!role->IsString()) {
err = "node.role must be string";
return false;
}
const std::string r = role->AsString("");
if (!r.empty() && r != "source" && r != "filter" && r != "sink") {
err = "node.role must be one of: source, filter, sink";
return false;
}
}
if (const SimpleJson* q = node.Find("queue")) {
std::string qerr;
if (!ValidateQueueCfg(*q, qerr)) {
err = "node.queue invalid: " + qerr;
return false;
}
}
if (const SimpleJson* aff = node.Find("cpu_affinity")) {
if (!aff->IsArray()) {
err = "node.cpu_affinity must be array";
return false;
}
for (const auto& c : aff->AsArray()) {
if (!c.IsNumber() || c.AsInt(-1) < 0) {
err = "node.cpu_affinity entries must be non-negative numbers";
return false;
}
}
}
return true;
}
inline bool ValidateEdgeCfg(const SimpleJson& edge, std::string& err) {
if (edge.IsArray()) {
const auto& a = edge.AsArray();
if (a.size() < 2) {
err = "edge array must be [from, to]";
return false;
}
if (!a[0].IsString() || !a[1].IsString()) {
err = "edge array entries must be strings";
return false;
}
if (a.size() >= 3) {
std::string qerr;
if (!ValidateQueueCfg(a[2], qerr)) {
err = "edge queue invalid: " + qerr;
return false;
}
}
return true;
}
if (edge.IsObject()) {
if (!IsStringNonEmpty(edge.Find("from")) || !IsStringNonEmpty(edge.Find("to"))) {
err = "edge object must have non-empty string 'from' and 'to'";
return false;
}
if (const SimpleJson* q = edge.Find("queue")) {
std::string qerr;
if (!ValidateQueueCfg(*q, qerr)) {
err = "edge.queue invalid: " + qerr;
return false;
}
}
return true;
}
err = "edge entry must be array or object";
return false;
}
inline bool ValidateExpandedRootConfig(const SimpleJson& root, std::string& err) {
if (!root.IsObject()) {
err = "root config must be object";
return false;
}
if (const SimpleJson* q = root.Find("queue")) {
std::string qerr;
if (!ValidateQueueCfg(*q, qerr)) {
err = "root.queue invalid: " + qerr;
return false;
}
}
if (const SimpleJson* g = root.Find("global")) {
if (!g->IsObject()) {
err = "root.global must be object";
return false;
}
}
const SimpleJson* graphs = root.Find("graphs");
if (!graphs || !graphs->IsArray()) {
err = "root missing 'graphs' array";
return false;
}
for (const auto& gv : graphs->AsArray()) {
if (!gv.IsObject()) {
err = "graph entry must be object";
return false;
}
if (!IsStringNonEmpty(gv.Find("name"))) {
err = "graph.name must be non-empty string";
return false;
}
const SimpleJson* nodes = gv.Find("nodes");
const SimpleJson* edges = gv.Find("edges");
if (!nodes || !nodes->IsArray()) {
err = "graph.nodes must be array";
return false;
}
if (!edges || !edges->IsArray()) {
err = "graph.edges must be array";
return false;
}
std::unordered_set<std::string> node_ids;
for (const auto& nv : nodes->AsArray()) {
std::string nerr;
if (!ValidateNodeCfg(nv, nerr)) {
err = "graph.nodes invalid: " + nerr;
return false;
}
const SimpleJson* id = nv.Find("id");
const std::string id_value = id ? id->AsString("") : "";
if (!id_value.empty() && !node_ids.insert(id_value).second) {
err = "graph.nodes duplicate id: " + id_value;
return false;
}
}
for (const auto& ev : edges->AsArray()) {
std::string eerr;
if (!ValidateEdgeCfg(ev, eerr)) {
err = "graph.edges invalid: " + eerr;
return false;
}
std::string from;
std::string to;
if (ev.IsArray()) {
const auto& a = ev.AsArray();
if (a.size() >= 2) {
from = a[0].AsString("");
to = a[1].AsString("");
}
} else if (ev.IsObject()) {
if (const SimpleJson* v = ev.Find("from")) {
from = v->AsString("");
}
if (const SimpleJson* v = ev.Find("to")) {
to = v->AsString("");
}
}
if (!from.empty() && node_ids.find(from) == node_ids.end()) {
err = "graph.edges unknown node: " + from;
return false;
}
if (!to.empty() && node_ids.find(to) == node_ids.end()) {
err = "graph.edges unknown node: " + to;
return false;
}
}
}
return true;
}
} // namespace rk3588