#pragma once #include #include #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 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