fad4006f60
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
4.0 KiB
4.0 KiB
id, title, status, type, domain, scope, priority, depends, blocks, related, created, updated, tags
| id | title | status | type | domain | scope | priority | depends | blocks | related | created | updated | tags | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0071f | Extraer `subprocess_streamer` a cpp/functions/core/ (sub-issue de 0071) | pendiente | feature |
|
registry-only | media | 2026-05-10 | 2026-05-17 |
Contexto
Sub-issue derivado de 0071 tras auditar paneles C++. La regla "rule of three" se cumple HOY para una primitiva Tier 4: spawn de subprocesos con captura de stdout/stderr en stream, sin wrapper compartido.
Tres reimplementaciones del mismo patron en projects/osint_graph/apps/graph_explorer/:
| Sitio | Linea | Mecanismo |
|---|---|---|
chat.cpp |
295 | popen(...) + fgets loop |
chat.cpp |
412 | execvp(...) con pipes manuales |
jobs.cpp |
817 | execvp(...) con pipes + read-thread |
extract_panel.cpp |
507 | execvp(...) para Python enricher |
Cada una hace: setup pipes, fork/exec, read loop, parse JSON line-by-line, push a UI queue. Codigo duplicado ~60-80 LoC en cada sitio.
Objetivo
Funcion subprocess_streamer en cpp/functions/core/ que encapsule:
- Spawn (POSIX
fork+execvp, WindowsCreateProcess) - Pipes para stdin/stdout/stderr
- Read-thread con callback por linea
- Cancel/kill
- Wait + exit code
API propuesta
namespace fn_core {
struct SubprocessConfig {
std::vector<std::string> argv; // [exe, arg1, arg2, ...]
std::vector<std::string> env; // ["KEY=VAL", ...]; vacio = heredar
std::string cwd; // vacio = heredar
bool merge_stderr_to_stdout = false;
std::function<void(const std::string&)> on_stdout_line;
std::function<void(const std::string&)> on_stderr_line;
std::function<void(int exit_code)> on_exit;
};
struct SubprocessHandle; // opaco
// Lanza subproceso. on_* se llaman desde un read-thread interno.
SubprocessHandle* subprocess_spawn(const SubprocessConfig& cfg);
// Escribe en stdin. Thread-safe. Devuelve bytes escritos o -1.
int subprocess_write_stdin(SubprocessHandle* h, const char* data, size_t n);
// Cierra stdin (EOF al child).
void subprocess_close_stdin(SubprocessHandle* h);
// Mata el proceso (SIGTERM en POSIX, TerminateProcess en Win).
void subprocess_kill(SubprocessHandle* h);
// Espera fin. Devuelve exit_code. Si ya termino, retorna inmediato.
int subprocess_wait(SubprocessHandle* h);
// Libera recursos. Si el proceso sigue vivo, lo mata primero.
void subprocess_destroy(SubprocessHandle* h);
} // namespace fn_core
Tests
- Spawn
echo hello→ on_stdout_line recibe "hello", exit 0. - Spawn
catcon stdin "abc\n" → on_stdout_line recibe "abc", exit 0 tras close_stdin. - Spawn
false→ exit 1. - Spawn comando inexistente → handle nullable o exit code distintivo.
- Kill proceso vivo → wait retorna codigo de señal.
cpp/apps/primitives_gallery/ añade demo "Subprocess Streamer" con boton "spawn echo hello" + lista de lineas recibidas.
Migracion de consumidores (orden)
- Crear
cpp/functions/core/subprocess_streamer.{h,cpp}+.md+ tests. - Migrar
chat.cppprimero (mas critico, define el flujo de error). Si funciona en chat → patron validado. - Migrar
jobs.cpp. - Migrar
extract_panel.cpp.
Cada migracion en su propio commit, validando por inspeccion manual que el panel sigue funcionando.
Definicion de hecho
subprocess_streamer.{h,cpp,md}registrado enregistry.db(fn index).- Tests pasan (al menos los 5 listados).
- 3 consumidores migrados (chat, jobs, extract_panel).
app.mdde graph_explorer actualizado:uses_functionsañadesubprocess_streamer_cpp_core.- LoC eliminadas en graph_explorer: ~150-200 (3 reimplementaciones colapsadas a 1 import).
Anti-patrones a evitar
- Async/promesa con
std::future— over-engineering. Callbacks bastan. - Buffering "smart" line-aware sobre bytes raw — usar
std::getlinesimple. - Soporte ptys (terminal real) — fuera de scope. Si una app necesita pty, abre issue propio.
- Prematura abstraccion de "shell vs exec". Solo
argvdirecto (execvp). Si alguien quiere shell pipes, lo hace enbash -c "...".