feat: scaffold project framework with engine, node skeleton, and passthrough node
- CMake build system with vcpkg dependency management - libdmf-node: Node interface, port definitions, WebSocket control server, node runner with MXL lifecycle management - libdmf-engine: Graph model (nodes/edges CRUD, serialization), FlowManager (UUID + V210 NMOS flow definitions), ProcessManager (fork/exec node processes), ApiServer (REST API for graph control) - Passthrough node: reads V210 grains from MXL, copies, writes to MXL - Unit tests for Graph and FlowManager (6 cases, 21 assertions) - MXL SDK as git submodule (symlinked from extern/mxl)
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
#include <dmf-engine/graph.hpp>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
namespace dmf_engine {
|
||||
|
||||
NodeId Graph::add_node(const std::string& type, const nlohmann::json& config) {
|
||||
auto id = type + "_" + std::to_string(next_node_num_++);
|
||||
GraphNode node;
|
||||
node.id = id;
|
||||
node.type = type;
|
||||
node.config = config;
|
||||
node.state = NodeState::Stopped;
|
||||
nodes_[id] = std::move(node);
|
||||
spdlog::info("Graph: added node '{}' type='{}'", id, type);
|
||||
return id;
|
||||
}
|
||||
|
||||
bool Graph::remove_node(const NodeId& node_id) {
|
||||
auto it = nodes_.find(node_id);
|
||||
if (it == nodes_.end()) {
|
||||
spdlog::warn("Graph: node '{}' not found", node_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<EdgeId> edges_to_remove;
|
||||
for (const auto& [eid, edge] : edges_) {
|
||||
if (edge.from_node == node_id || edge.to_node == node_id) {
|
||||
edges_to_remove.push_back(eid);
|
||||
}
|
||||
}
|
||||
for (const auto& eid : edges_to_remove) {
|
||||
edges_.erase(eid);
|
||||
spdlog::info("Graph: removed edge '{}' (connected to removed node '{}')", eid, node_id);
|
||||
}
|
||||
|
||||
nodes_.erase(it);
|
||||
spdlog::info("Graph: removed node '{}'", node_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
const GraphNode* Graph::get_node(const NodeId& node_id) const {
|
||||
auto it = nodes_.find(node_id);
|
||||
return it != nodes_.end() ? &it->second : nullptr;
|
||||
}
|
||||
|
||||
std::vector<GraphNode> Graph::get_nodes() const {
|
||||
std::vector<GraphNode> result;
|
||||
for (const auto& [_, node] : nodes_) {
|
||||
result.push_back(node);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
EdgeId Graph::add_edge(const NodeId& from_node, const PortId& from_port,
|
||||
const NodeId& to_node, const PortId& to_port,
|
||||
const FlowId& flow_id, const nlohmann::json& flow_def) {
|
||||
auto id = from_node + ":" + from_port + "->" + to_node + ":" + to_port;
|
||||
GraphEdge edge;
|
||||
edge.id = id;
|
||||
edge.from_node = from_node;
|
||||
edge.from_port = from_port;
|
||||
edge.to_node = to_node;
|
||||
edge.to_port = to_port;
|
||||
edge.flow_id = flow_id;
|
||||
edge.flow_def = flow_def;
|
||||
edges_[id] = std::move(edge);
|
||||
spdlog::info("Graph: added edge '{}' flow_id={}", id, flow_id);
|
||||
return id;
|
||||
}
|
||||
|
||||
bool Graph::remove_edge(const EdgeId& edge_id) {
|
||||
auto it = edges_.find(edge_id);
|
||||
if (it == edges_.end()) {
|
||||
spdlog::warn("Graph: edge '{}' not found", edge_id);
|
||||
return false;
|
||||
}
|
||||
edges_.erase(it);
|
||||
spdlog::info("Graph: removed edge '{}'", edge_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<GraphEdge> Graph::get_edges() const {
|
||||
std::vector<GraphEdge> result;
|
||||
for (const auto& [_, edge] : edges_) {
|
||||
result.push_back(edge);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<GraphEdge> Graph::get_edges_for_node(const NodeId& node_id) const {
|
||||
std::vector<GraphEdge> result;
|
||||
for (const auto& [_, edge] : edges_) {
|
||||
if (edge.from_node == node_id || edge.to_node == node_id) {
|
||||
result.push_back(edge);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
nlohmann::json Graph::serialize() const {
|
||||
auto j = nlohmann::json::object();
|
||||
|
||||
auto nodes_arr = nlohmann::json::array();
|
||||
for (const auto& [id, node] : nodes_) {
|
||||
nodes_arr.push_back({
|
||||
{"id", node.id},
|
||||
{"type", node.type},
|
||||
{"config", node.config},
|
||||
{"state", static_cast<int>(node.state)},
|
||||
{"control_port", node.control_port},
|
||||
{"pid", node.pid},
|
||||
});
|
||||
}
|
||||
j["nodes"] = nodes_arr;
|
||||
|
||||
auto edges_arr = nlohmann::json::array();
|
||||
for (const auto& [id, edge] : edges_) {
|
||||
edges_arr.push_back({
|
||||
{"id", edge.id},
|
||||
{"from_node", edge.from_node},
|
||||
{"from_port", edge.from_port},
|
||||
{"to_node", edge.to_node},
|
||||
{"to_port", edge.to_port},
|
||||
{"flow_id", edge.flow_id},
|
||||
});
|
||||
}
|
||||
j["edges"] = edges_arr;
|
||||
|
||||
return j;
|
||||
}
|
||||
|
||||
} // namespace dmf_engine
|
||||
Reference in New Issue
Block a user