5b5ffa1308
- 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)
98 lines
2.8 KiB
C++
98 lines
2.8 KiB
C++
#include <dmf-engine/process_manager.hpp>
|
|
|
|
#include <spdlog/spdlog.h>
|
|
|
|
#include <cstdlib>
|
|
#include <filesystem>
|
|
#include <signal.h>
|
|
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
|
#include <unistd.h>
|
|
|
|
namespace dmf_engine {
|
|
|
|
std::string ProcessManager::find_node_binary(const std::string& node_type) const {
|
|
std::string binary_name = "dmf-node-" + node_type;
|
|
|
|
if (const char* env_path = std::getenv("DMF_NODE_PATH")) {
|
|
auto candidate = std::filesystem::path(env_path) / binary_name;
|
|
if (std::filesystem::exists(candidate)) {
|
|
return candidate.string();
|
|
}
|
|
}
|
|
|
|
if (const char* self_dir_env = std::getenv("DMF_STUDIO_BIN_DIR")) {
|
|
auto candidate = std::filesystem::path(self_dir_env) / binary_name;
|
|
if (std::filesystem::exists(candidate)) {
|
|
return candidate.string();
|
|
}
|
|
}
|
|
|
|
return binary_name;
|
|
}
|
|
|
|
bool ProcessManager::start_node(GraphNode& node, const std::string& mxl_domain, uint16_t base_port) {
|
|
if (node.state == NodeState::Running) {
|
|
spdlog::warn("ProcessManager: node '{}' is already running", node.id);
|
|
return true;
|
|
}
|
|
|
|
auto binary = find_node_binary(node.type);
|
|
node.control_port = base_port;
|
|
|
|
pid_t pid = fork();
|
|
if (pid < 0) {
|
|
spdlog::error("ProcessManager: fork() failed for node '{}': {}", node.id, strerror(errno));
|
|
return false;
|
|
}
|
|
|
|
if (pid == 0) {
|
|
std::string port_str = std::to_string(node.control_port);
|
|
std::string config_str = node.config.dump();
|
|
|
|
execlp(binary.c_str(), binary.c_str(),
|
|
"--node-id", node.id.c_str(),
|
|
"--control-port", port_str.c_str(),
|
|
"--mxl-domain", mxl_domain.c_str(),
|
|
"--config", config_str.c_str(),
|
|
nullptr);
|
|
|
|
spdlog::error("ProcessManager: execlp failed for '{}': {}", binary, strerror(errno));
|
|
_exit(1);
|
|
}
|
|
|
|
node.pid = pid;
|
|
node.state = NodeState::Running;
|
|
spdlog::info("ProcessManager: started node '{}' pid={} port={}", node.id, pid, node.control_port);
|
|
return true;
|
|
}
|
|
|
|
bool ProcessManager::stop_node(GraphNode& node) {
|
|
if (node.state != NodeState::Running || node.pid <= 0) {
|
|
spdlog::warn("ProcessManager: node '{}' is not running", node.id);
|
|
return true;
|
|
}
|
|
|
|
if (kill(node.pid, SIGTERM) != 0) {
|
|
spdlog::error("ProcessManager: failed to send SIGTERM to node '{}': {}", node.id, strerror(errno));
|
|
return false;
|
|
}
|
|
|
|
int status = 0;
|
|
waitpid(node.pid, &status, 0);
|
|
|
|
spdlog::info("ProcessManager: stopped node '{}' pid={}", node.id, node.pid);
|
|
node.pid = 0;
|
|
node.state = NodeState::Stopped;
|
|
return true;
|
|
}
|
|
|
|
void ProcessManager::stop_all() {
|
|
}
|
|
|
|
bool ProcessManager::is_running(const NodeId& node_id) const {
|
|
return false;
|
|
}
|
|
|
|
} // namespace dmf_engine
|