#include #include #include #include #include #include #include #include namespace dmf_engine { void NodeControlClient::register_node(const std::string& node_id, uint16_t port) { node_ports_[node_id] = port; spdlog::info("NodeControlClient: registered node '{}' on port {}", node_id, port); } void NodeControlClient::unregister_node(const std::string& node_id) { node_ports_.erase(node_id); } uint16_t NodeControlClient::get_port(const std::string& node_id) const { auto it = node_ports_.find(node_id); return it != node_ports_.end() ? it->second : 0; } bool NodeControlClient::send_command(uint16_t port, const std::string& json_cmd) { int fd = socket(AF_INET, SOCK_STREAM, 0); if (fd < 0) { spdlog::error("NodeControlClient: socket() failed: {}", strerror(errno)); return false; } struct timeval tv; tv.tv_sec = 2; tv.tv_usec = 0; setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); struct sockaddr_in addr; std::memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr); if (connect(fd, reinterpret_cast(&addr), sizeof(addr)) < 0) { spdlog::error("NodeControlClient: connect to port {} failed: {}", port, strerror(errno)); close(fd); return false; } std::ostringstream req; req << "POST /cmd HTTP/1.1\r\n" << "Host: 127.0.0.1:" << port << "\r\n" << "Content-Type: application/json\r\n" << "Content-Length: " << json_cmd.size() << "\r\n" << "Connection: close\r\n" << "\r\n" << json_cmd; auto request = req.str(); auto sent = write(fd, request.data(), request.size()); if (sent != static_cast(request.size())) { spdlog::error("NodeControlClient: write failed on port {}", port); close(fd); return false; } char resp_buf[4096] = {}; auto n = read(fd, resp_buf, sizeof(resp_buf) - 1); close(fd); if (n <= 0) { spdlog::error("NodeControlClient: read failed on port {}", port); return false; } std::string resp(resp_buf, n); bool ok = resp.find("200 OK") != std::string::npos || resp.find("201 Created") != std::string::npos; if (!ok) { spdlog::warn("NodeControlClient: command failed on port {}: {}", port, resp.substr(0, 100)); } return ok; } std::string NodeControlClient::send_command_with_response(uint16_t port, const std::string& json_cmd) { int fd = socket(AF_INET, SOCK_STREAM, 0); if (fd < 0) { spdlog::error("NodeControlClient: socket() failed: {}", strerror(errno)); return ""; } struct timeval tv; tv.tv_sec = 2; tv.tv_usec = 0; setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); struct sockaddr_in addr; std::memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr); if (connect(fd, reinterpret_cast(&addr), sizeof(addr)) < 0) { spdlog::error("NodeControlClient: connect to port {} failed: {}", port, strerror(errno)); close(fd); return ""; } std::ostringstream req; req << "POST /cmd HTTP/1.1\r\n" << "Host: 127.0.0.1:" << port << "\r\n" << "Content-Type: application/json\r\n" << "Content-Length: " << json_cmd.size() << "\r\n" << "Connection: close\r\n" << "\r\n" << json_cmd; auto request = req.str(); auto sent = write(fd, request.data(), request.size()); if (sent != static_cast(request.size())) { spdlog::error("NodeControlClient: write failed on port {}", port); close(fd); return ""; } std::string full_resp; char resp_buf[4096]; while (true) { auto n = read(fd, resp_buf, sizeof(resp_buf)); if (n <= 0) break; full_resp.append(resp_buf, n); } close(fd); auto body_start = full_resp.find("\r\n\r\n"); if (body_start == std::string::npos) return ""; return full_resp.substr(body_start + 4); } } // namespace dmf_engine