5e6a974a5d
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
161 lines
5.7 KiB
Markdown
161 lines
5.7 KiB
Markdown
---
|
|
id: "0033"
|
|
title: "C++ http_inspector + websocket_client"
|
|
status: pendiente
|
|
type: feature
|
|
domain:
|
|
- cpp-stack
|
|
scope: multi-app
|
|
priority: baja
|
|
depends: []
|
|
blocks: []
|
|
related: []
|
|
created: 2026-05-17
|
|
updated: 2026-05-17
|
|
tags: []
|
|
---
|
|
# 0033 — C++ http_inspector + websocket_client
|
|
|
|
## APP Metadata
|
|
|
|
| Campo | Valor |
|
|
|-------|-------|
|
|
| **ID** | 0033 |
|
|
| **Estado** | pendiente |
|
|
| **Prioridad** | baja |
|
|
| **Tipo** | feature — C++ core (cpp/functions/core) |
|
|
|
|
## Dependencias
|
|
|
|
`text_editor_cpp_core` (issue 0025) recomendado para editar bodies; fallback a `InputTextMultiline`. `time_series_buffer_cpp_core`.
|
|
|
|
**Desbloquea:** debugging visual de APIs internas y feeds en tiempo real desde C++ apps. Util para apps de monitoring que se conectan a servicios propios.
|
|
|
|
---
|
|
|
|
## Objetivo
|
|
|
|
Dos componentes complementarios:
|
|
|
|
1. **`http_inspector_cpp_core`** — panel ImGui tipo Postman minimo: input URL, dropdown method (GET/POST/PUT/DELETE/PATCH), headers (key/value list), body, boton Send. Muestra status, headers de respuesta, body con pretty-print JSON.
|
|
2. **`websocket_client_cpp_core`** — panel WebSocket: input ws://… , botones Connect/Disconnect, area de mensajes (timeline), input para enviar texto, contador msg/s y plot rate.
|
|
|
|
Vendorea [cpp-httplib](https://github.com/yhirose/cpp-httplib) (MIT, header-only) para HTTP. Para WS usa la API client de cpp-httplib (>=0.20 trae soporte ws basico) o vendorea [websocketpp](https://github.com/zaphoyd/websocketpp). Decidir en Fase 1.
|
|
|
|
Demo en `primitives_gallery` con un endpoint HTTP de prueba (httpbin.org) y un WS echo (`wss://echo.websocket.events`).
|
|
|
|
## Contexto
|
|
|
|
Apps C++ que consumen APIs internas (registry_api, deploy_server) suelen requerir scripts curl/Postman aparte para debugging. Tener un inspector embebido reduce friccion.
|
|
|
|
## Arquitectura
|
|
|
|
```
|
|
cpp/
|
|
├── vendor/cpp-httplib/
|
|
│ └── httplib.h # NEW (header-only, MIT)
|
|
├── functions/core/
|
|
│ ├── http_inspector.h/.cpp/.md # NEW (impure component)
|
|
│ └── websocket_client.h/.cpp/.md # NEW (impure component)
|
|
└── apps/primitives_gallery/
|
|
├── demos_net.cpp # NEW
|
|
├── demos.h # MOD
|
|
├── main.cpp # MOD
|
|
└── CMakeLists.txt # MOD
|
|
cpp/CMakeLists.txt # MOD
|
|
```
|
|
|
|
### API propuesta
|
|
|
|
```cpp
|
|
namespace fn {
|
|
|
|
struct HttpHeader { std::string key, value; };
|
|
struct HttpInspectorState {
|
|
std::string url = "https://httpbin.org/get";
|
|
std::string method = "GET";
|
|
std::vector<HttpHeader> headers;
|
|
std::string body;
|
|
int last_status = 0;
|
|
std::vector<HttpHeader> last_headers;
|
|
std::string last_body;
|
|
double last_ms = 0.0;
|
|
bool in_flight = false; // request en background
|
|
std::string error;
|
|
};
|
|
void http_inspector(const char* id, HttpInspectorState&, ImVec2 size = {-1, -1});
|
|
|
|
struct WsMessage { double t; bool incoming; std::string text; };
|
|
struct WebSocketClientState {
|
|
std::string url = "wss://echo.websocket.events";
|
|
bool connected = false;
|
|
std::string send_buf;
|
|
std::vector<WsMessage> messages; // capped at 500
|
|
float rate_msgs_s = 0.f;
|
|
std::string error;
|
|
};
|
|
void websocket_client(const char* id, WebSocketClientState&, ImVec2 size = {-1, -1});
|
|
}
|
|
```
|
|
|
|
## Tareas
|
|
|
|
### Fase 1 — Vendor + decision WS
|
|
|
|
- 1.1 Vendorear `httplib.h` (pinear version reciente con TLS opcional).
|
|
- 1.2 Decidir cliente WS:
|
|
- Opcion A: cpp-httplib `WebSocketClient` si la version vendoreada lo trae.
|
|
- Opcion B: vendorear `websocketpp` (header-only-ish, depende de Asio header-only).
|
|
- 1.3 Documentar la decision en `cpp/vendor/<lib>/README.md`.
|
|
|
|
### Fase 2 — http_inspector
|
|
|
|
- 2.1 Implementar el componente. Request en background con `std::thread` (ver `process_runner_cpp_core` como patrón).
|
|
- 2.2 Pretty-print: si `Content-Type: application/json`, formatear con un mini parser/printer JSON (o copiar uno minimal; no necesitamos validacion exhaustiva).
|
|
- 2.3 `.md` con frontmatter (`kind: component`, `purity: impure`, `error_type`).
|
|
|
|
### Fase 3 — websocket_client
|
|
|
|
- 3.1 Implementar `connect/disconnect` en thread; lockear cola de mensajes con mutex; copiar a `state.messages` en `websocket_client()` (main thread).
|
|
- 3.2 Calcular `rate_msgs_s` como contador por segundo con ventana deslizante (puede usar `time_series_buffer_cpp_core`).
|
|
- 3.3 `.md`.
|
|
|
|
### Fase 4 — Gallery demo
|
|
|
|
- 4.1 `demos_net.cpp` con `demo_http_inspector()` y `demo_websocket_client()`.
|
|
- 4.2 Registrar.
|
|
|
|
### Fase 5 — Tests + docs
|
|
|
|
- 5.1 Test pretty-print JSON sobre payload conocido.
|
|
- 5.2 Test ratelimit del rate_msgs_s.
|
|
- 5.3 Smoke test (opcional, requires net): GET a 127.0.0.1 contra un servidor levantado en el test.
|
|
- 5.4 `./fn index` + `./fn show`.
|
|
|
|
## Ejemplo de uso
|
|
|
|
```cpp
|
|
fn::HttpInspectorState http;
|
|
fn::WebSocketClientState ws;
|
|
|
|
fn::run_app("net", [&]{
|
|
if (ImGui::BeginTabBar("net")) {
|
|
if (ImGui::BeginTabItem("HTTP")) { fn::http_inspector("##h", http); ImGui::EndTabItem(); }
|
|
if (ImGui::BeginTabItem("WS")) { fn::websocket_client("##w", ws); ImGui::EndTabItem(); }
|
|
ImGui::EndTabBar();
|
|
}
|
|
});
|
|
```
|
|
|
|
## Decisiones de diseño
|
|
|
|
- **cpp-httplib** vs libcurl: header-only gana en complejidad de build. TLS via OpenSSL si esta disponible; degradar a HTTP si no.
|
|
- **Mensajes WS capped**: 500 maximo en buffer para no crecer indefinidamente; descartar oldest.
|
|
- **Sin authentication helpers**: el header `Authorization` se mete a mano. UX simple.
|
|
|
|
## Riesgos
|
|
|
|
- **TLS**: cpp-httplib requiere OpenSSL para `https://`. Documentar en CMake como opt-in.
|
|
- **WS reconnect**: no implementar auto-reconnect en MVP. El usuario reconecta manualmente.
|
|
- **Threading**: cuidado con marshalling de strings entre thread y UI. Mutex obligatorio en mensajes.
|