Files
odr_console/runner.cpp
T
egutierrez d3af7d54ff chore: auto-commit (6 archivos)
- CMakeLists.txt
- main.cpp
- data_collectors.cpp
- data_collectors.h
- runner.cpp
- runner.h

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 13:30:27 +02:00

125 lines
3.2 KiB
C++

#include "runner.h"
#include <atomic>
#include <chrono>
#include <cstdio>
#include <cstdlib>
#include <filesystem>
#include <fstream>
#include <sstream>
namespace fs = std::filesystem;
namespace odr {
namespace {
long long now_ms() {
using namespace std::chrono;
return duration_cast<milliseconds>(
system_clock::now().time_since_epoch()).count();
}
std::string make_uid() {
static std::atomic<int> ctr{0};
long long ts = now_ms();
int n = ctr.fetch_add(1, std::memory_order_relaxed);
char buf[64];
std::snprintf(buf, sizeof(buf), "%lld_%05d", ts, n);
return buf;
}
bool write_file(const fs::path& p, const std::string& bytes) {
std::ofstream f(p, std::ios::binary | std::ios::trunc);
if (!f.is_open()) return false;
f.write(bytes.data(), (std::streamsize)bytes.size());
return f.good();
}
std::string read_file(const fs::path& p) {
std::ifstream f(p, std::ios::binary);
if (!f.is_open()) return "";
std::ostringstream ss;
ss << f.rdbuf();
return ss.str();
}
// Quote para shell: encierra en comillas dobles, escapa los " internos.
// Suficiente para paths del registry — no tocamos shell metacharacters
// porque no hay input de usuario directo (paths controlados por la app).
std::string sh_quote(const std::string& s) {
std::string out;
out.reserve(s.size() + 2);
out.push_back('"');
for (char c : s) {
if (c == '"' || c == '\\' || c == '$' || c == '`') {
out.push_back('\\');
}
out.push_back(c);
}
out.push_back('"');
return out;
}
} // namespace
RunResult run_collector(const std::string& python_exe,
const std::string& run_py,
const std::string& tmp_dir,
const std::string& ctx_json) {
RunResult r;
std::error_code ec;
fs::create_directories(tmp_dir, ec);
if (ec) {
r.stderr_str = "create_directories failed: " + ec.message();
return r;
}
std::string uid = make_uid();
fs::path ctx_path = fs::path(tmp_dir) / ("ctx_" + uid + ".json");
fs::path out_path = fs::path(tmp_dir) / ("out_" + uid + ".json");
fs::path err_path = fs::path(tmp_dir) / ("err_" + uid + ".log");
if (!write_file(ctx_path, ctx_json)) {
r.stderr_str = "write ctx failed";
return r;
}
std::string cmd =
sh_quote(python_exe) + " " + sh_quote(run_py)
+ " < " + sh_quote(ctx_path.string())
+ " > " + sh_quote(out_path.string())
+ " 2> " + sh_quote(err_path.string());
long long t0 = now_ms();
int rc = std::system(cmd.c_str());
r.duration_ms = now_ms() - t0;
#if defined(__unix__) || defined(__APPLE__)
// POSIX: WEXITSTATUS para extraer exit code real.
if (rc != -1 && WIFEXITED(rc)) {
r.exit_code = WEXITSTATUS(rc);
} else {
r.exit_code = rc;
}
#else
r.exit_code = rc;
#endif
r.stdout_str = read_file(out_path);
r.stderr_str = read_file(err_path);
// Cleanup salvo si fallo (dejar para debug).
if (r.exit_code == 0) {
std::error_code rmec;
fs::remove(ctx_path, rmec);
fs::remove(out_path, rmec);
fs::remove(err_path, rmec);
}
return r;
}
} // namespace odr