216 lines
6.8 KiB
C++
216 lines
6.8 KiB
C++
#include "graph_manager.h"
|
|
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include <map>
|
|
#include <set>
|
|
|
|
namespace rk3588 {
|
|
|
|
Graph::Graph(std::string name) : name_(std::move(name)) {}
|
|
|
|
Graph::~Graph() { Stop(); }
|
|
|
|
bool Graph::Build(const SimpleJson& graph_cfg, PluginLoader& loader, size_t default_queue_size,
|
|
QueueDropStrategy default_strategy, std::string& err) {
|
|
const auto& obj = graph_cfg.AsObject();
|
|
auto name_it = obj.find("name");
|
|
if (name_it != obj.end() && name_it->second.IsString()) {
|
|
name_ = name_it->second.AsString(name_);
|
|
}
|
|
|
|
// Parse nodes
|
|
auto nodes_it = obj.find("nodes");
|
|
if (nodes_it == obj.end() || !nodes_it->second.IsArray()) {
|
|
err = "Graph missing 'nodes' array";
|
|
return false;
|
|
}
|
|
|
|
for (const auto& node_val : nodes_it->second.AsArray()) {
|
|
if (!node_val.IsObject()) {
|
|
err = "Node entry is not object";
|
|
return false;
|
|
}
|
|
NodeEntry entry;
|
|
entry.config = node_val;
|
|
entry.id = node_val.ValueOr<std::string>("id", "");
|
|
entry.type = node_val.ValueOr<std::string>("type", "");
|
|
entry.enabled = node_val.ValueOr<bool>("enable", true);
|
|
if (entry.id.empty() || entry.type.empty()) {
|
|
err = "Node missing id or type";
|
|
return false;
|
|
}
|
|
nodes_.push_back(std::move(entry));
|
|
}
|
|
|
|
// Parse edges
|
|
auto edges_it = obj.find("edges");
|
|
if (edges_it == obj.end() || !edges_it->second.IsArray()) {
|
|
err = "Graph missing 'edges' array";
|
|
return false;
|
|
}
|
|
|
|
std::map<std::string, NodeEntry*> id_to_node;
|
|
for (auto& n : nodes_) {
|
|
id_to_node[n.id] = &n;
|
|
}
|
|
|
|
for (const auto& edge_val : edges_it->second.AsArray()) {
|
|
if (!edge_val.IsArray() || edge_val.AsArray().size() != 2) {
|
|
err = "Edge must be [from, to]";
|
|
return false;
|
|
}
|
|
const auto& edge_arr = edge_val.AsArray();
|
|
std::string from = edge_arr[0].AsString("");
|
|
std::string to = edge_arr[1].AsString("");
|
|
if (from.empty() || to.empty()) {
|
|
err = "Edge has empty endpoint";
|
|
return false;
|
|
}
|
|
auto from_it = id_to_node.find(from);
|
|
auto to_it = id_to_node.find(to);
|
|
if (from_it == id_to_node.end() || to_it == id_to_node.end()) {
|
|
err = "Edge references unknown node";
|
|
return false;
|
|
}
|
|
size_t qsize = default_queue_size;
|
|
QueueDropStrategy strategy = default_strategy;
|
|
if (const auto* qcfg = edge_val.Find("queue")) {
|
|
if (qcfg->IsObject()) {
|
|
qsize = static_cast<size_t>(qcfg->ValueOr<int>("size", static_cast<int>(default_queue_size)));
|
|
std::string strat = qcfg->ValueOr<std::string>("strategy", "drop_oldest");
|
|
if (strat == "drop_oldest") strategy = QueueDropStrategy::DropOldest;
|
|
else strategy = QueueDropStrategy::Block;
|
|
}
|
|
}
|
|
auto queue = std::make_shared<SpscQueue<FramePtr>>(qsize, strategy);
|
|
from_it->second->context.output_queues.push_back(queue);
|
|
// For now support single input per node; first edge wins.
|
|
if (!to_it->second->context.input_queue) {
|
|
to_it->second->context.input_queue = queue;
|
|
}
|
|
}
|
|
|
|
// Instantiate nodes via plugins
|
|
for (auto& entry : nodes_) {
|
|
if (!entry.enabled) continue;
|
|
std::string load_err;
|
|
entry.node = loader.Create(entry.type, load_err);
|
|
if (!entry.node) {
|
|
err = load_err;
|
|
return false;
|
|
}
|
|
if (!entry.node->Init(entry.config, entry.context)) {
|
|
err = "Init failed for node " + entry.id;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Graph::Start() {
|
|
for (auto& entry : nodes_) {
|
|
if (!entry.enabled || !entry.node) continue;
|
|
if (!entry.node->Start()) {
|
|
std::cerr << "[Graph] failed to start node: " << entry.id << "\n";
|
|
return false;
|
|
}
|
|
}
|
|
std::cout << "[Graph] started graph " << name_ << " with " << nodes_.size() << " nodes\n";
|
|
return true;
|
|
}
|
|
|
|
void Graph::Stop() {
|
|
for (auto it = nodes_.rbegin(); it != nodes_.rend(); ++it) {
|
|
if (it->node) {
|
|
it->node->Stop();
|
|
}
|
|
if (it->context.input_queue) it->context.input_queue->Stop();
|
|
for (auto& q : it->context.output_queues) q->Stop();
|
|
}
|
|
}
|
|
|
|
GraphManager::GraphManager(std::string plugin_dir)
|
|
: loader_(std::move(plugin_dir)) {}
|
|
|
|
GraphManager::~GraphManager() { StopAll(); }
|
|
|
|
bool GraphManager::LoadConfigFile(const std::string& path, SimpleJson& out, std::string& err) {
|
|
std::ifstream ifs(path);
|
|
if (!ifs.is_open()) {
|
|
err = "Failed to open config: " + path;
|
|
return false;
|
|
}
|
|
std::string content((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
|
|
return ParseSimpleJson(content, out, err);
|
|
}
|
|
|
|
bool GraphManager::Build(const SimpleJson& root_cfg, std::string& err) {
|
|
auto graphs_it = root_cfg.AsObject().find("graphs");
|
|
if (graphs_it == root_cfg.AsObject().end() || !graphs_it->second.IsArray()) {
|
|
err = "Root config missing 'graphs' array";
|
|
return false;
|
|
}
|
|
|
|
size_t default_queue_size = 8;
|
|
QueueDropStrategy default_strategy = QueueDropStrategy::DropOldest;
|
|
if (const auto* queue_cfg = root_cfg.Find("queue")) {
|
|
if (queue_cfg->IsObject()) {
|
|
default_queue_size = static_cast<size_t>(queue_cfg->ValueOr<int>("size", 8));
|
|
std::string strategy = queue_cfg->ValueOr<std::string>("strategy", "drop_oldest");
|
|
if (strategy == "block") default_strategy = QueueDropStrategy::Block;
|
|
}
|
|
}
|
|
|
|
for (const auto& graph_val : graphs_it->second.AsArray()) {
|
|
if (!graph_val.IsObject()) {
|
|
err = "Graph entry is not object";
|
|
return false;
|
|
}
|
|
std::string name = graph_val.ValueOr<std::string>("name", "noname");
|
|
auto graph = std::make_unique<Graph>(name);
|
|
if (!graph->Build(graph_val, loader_, default_queue_size, default_strategy, err)) {
|
|
return false;
|
|
}
|
|
graphs_.push_back(std::move(graph));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool GraphManager::StartAll() {
|
|
for (auto& g : graphs_) {
|
|
if (!g->Start()) {
|
|
return false;
|
|
}
|
|
}
|
|
{
|
|
std::lock_guard<std::mutex> lock(mu_);
|
|
running_ = true;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void GraphManager::StopAll() {
|
|
{
|
|
std::lock_guard<std::mutex> lock(mu_);
|
|
if (!running_) return;
|
|
running_ = false;
|
|
}
|
|
for (auto& g : graphs_) {
|
|
g->Stop();
|
|
}
|
|
cv_.notify_all();
|
|
}
|
|
|
|
void GraphManager::RequestStop() {
|
|
StopAll();
|
|
}
|
|
|
|
void GraphManager::BlockUntilStop() {
|
|
std::unique_lock<std::mutex> lock(mu_);
|
|
cv_.wait(lock, [&] { return !running_; });
|
|
}
|
|
|
|
} // namespace rk3588
|