From f89ad0d9bc47d74123385d2c22d31463f8dd4fa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20P=C3=A9rez?= Date: Fri, 18 Sep 2026 20:31:37 -0300 Subject: [PATCH] docs(plugins): document example plugin usage, config, and output format --- docs/en/server/user-guide/plugins.md | 66 +++++++++++++++++++++++++--- docs/es/server/user-guide/plugins.md | 66 +++++++++++++++++++++++++--- 2 files changed, 118 insertions(+), 14 deletions(-) diff --git a/docs/en/server/user-guide/plugins.md b/docs/en/server/user-guide/plugins.md index 3acbab2..6e53362 100644 --- a/docs/en/server/user-guide/plugins.md +++ b/docs/en/server/user-guide/plugins.md @@ -182,16 +182,68 @@ flowchart TD --- -## Reference example +## Using the example plugin -Study `plugins/example/` in the repository root: +`plugins/example/` is a working, disabled-by-default plugin — enable it to see the framework in action, or copy its tree as a starting point for your own ([Clean architecture in plugins](#clean-architecture-in-plugins) above). -- `enabled: false` in committed `config.yaml` (no secrets). -- `DEBUG` log on every event. -- Writes one JSON file per session under `example-events/` on `VoiceCallEnd` / `UnitDataEnd`. -- Tests in `plugins/example/tests/`. +### What it does -To try it: set `enabled: true`, reload, make a call, inspect `example-events/.json`. +- Logs a `DEBUG` line `(EXAMPLE) …` for every bus event (`VoiceCallStart`/`Frame`/`End`, `UnitDataStart`/`Frame`/`End`). +- Tracks each session, keyed by `(origin_system, stream_id)`, and on `VoiceCallEnd` / `UnitDataEnd` writes one JSON file with call metadata, duration, and frame/packet count. +- No HTTP calls, no filters, no secrets — safe to enable as-is (`plugins/example/plugin/application/plugin_impl.py`). + +### Enable it + +```yaml +# plugins/example/config.yaml +enabled: true +output_dir: example-events # relative to the project root; created on first write +``` + +```bash +systemctl reload adn-server # SIGHUP — PluginManager rescans plugins/ +``` + +### Config options + +| Key | Default | Role | +|-----|---------|------| +| `enabled` | `false` | Must be `true` to load the plugin | +| `output_dir` | `example-events` | Where session JSON files are written, relative to the server's project root | + +### Output + +One file per session: `/.json` (`stream_id` as a plain integer, not hex), pretty-printed with sorted keys. The write runs off the reactor thread via `defer_to_thread`, so it never blocks call handling. + +Example — a group voice call on `SYSTEM` that ended after 2.16s, relayed onward to `OBP-USA`: + +```json +{ + "call_family": "GROUP", + "direction": "RX", + "dst_id": 91, + "duration_s": 2.16, + "ended_at": "2026-09-18T21:05:11.532000Z", + "event_kind": "voice", + "forwarded_systems": ["OBP-USA"], + "frame_count": 36, + "is_proxy_ingress": false, + "is_synthetic": false, + "origin_system": "SYSTEM", + "peer_id": 312000, + "pkt_time": 1758229511.532, + "server_id": 73010, + "slot": 1, + "src_id": 7300391, + "started_at": "2026-09-18T21:05:09.372000Z", + "stream_id": 1234567890, + "system_mode": "MASTER" +} +``` + +For unit-data sessions `event_kind` is `"unit_data"` and the count field is `packet_count` instead of `frame_count`. Legs that crossed an OpenBridge also carry `obp_source_server_id`, `obp_hops`, `obp_source_rptr_id`, `ber`, `rssi` when present (see [Event types](#event-types) above). + +To try it end to end: set `enabled: true`, reload, make a call or send unit data through the server, then check `example-events/.json` under the project root. Its own tests (`plugins/example/tests/`) cover session tracking and the JSON record shape — see [Tests](#tests) below to run them. --- diff --git a/docs/es/server/user-guide/plugins.md b/docs/es/server/user-guide/plugins.md index 8b92866..83b575d 100644 --- a/docs/es/server/user-guide/plugins.md +++ b/docs/es/server/user-guide/plugins.md @@ -182,16 +182,68 @@ flowchart TD --- -## Ejemplo de referencia +## Usando el plugin de ejemplo -Estudia `plugins/example/` en la raíz del repositorio: +`plugins/example/` es un plugin funcional, deshabilitado por defecto — actívalo para ver el framework en acción, o copia su estructura como punto de partida para el tuyo ([Clean architecture en plugins](#clean-architecture-en-plugins) más arriba). -- `enabled: false` en el `config.yaml` versionado (sin secretos). -- Log `DEBUG` en cada evento. -- Escribe un JSON por sesión en `example-events/` al `VoiceCallEnd` / `UnitDataEnd`. -- Tests en `plugins/example/tests/`. +### Qué hace -Para probarlo: `enabled: true`, reload, haz una llamada, revisa `example-events/.json`. +- Loguea una línea `DEBUG` `(EXAMPLE) …` por cada evento del bus (`VoiceCallStart`/`Frame`/`End`, `UnitDataStart`/`Frame`/`End`). +- Trackea cada sesión, identificada por `(origin_system, stream_id)`, y al `VoiceCallEnd` / `UnitDataEnd` escribe un JSON con metadata de la llamada, duración y cantidad de frames/paquetes. +- Sin llamadas HTTP, sin filtros, sin secretos — seguro de activar tal cual (`plugins/example/plugin/application/plugin_impl.py`). + +### Activarlo + +```yaml +# plugins/example/config.yaml +enabled: true +output_dir: example-events # relativo al project root; se crea en la primera escritura +``` + +```bash +systemctl reload adn-server # SIGHUP — PluginManager reescanea plugins/ +``` + +### Opciones de configuración + +| Clave | Default | Función | +|-------|---------|---------| +| `enabled` | `false` | Debe ser `true` para cargar el plugin | +| `output_dir` | `example-events` | Dónde se escriben los JSON de sesión, relativo al project root del servidor | + +### Salida + +Un archivo por sesión: `/.json` (`stream_id` como entero plano, no hex), con formato indentado y claves ordenadas. La escritura corre fuera del hilo del reactor vía `defer_to_thread`, así que nunca bloquea el manejo de llamadas. + +Ejemplo — una llamada de voz grupal en `SYSTEM` que terminó tras 2.16s, retransmitida a `OBP-USA`: + +```json +{ + "call_family": "GROUP", + "direction": "RX", + "dst_id": 91, + "duration_s": 2.16, + "ended_at": "2026-09-18T21:05:11.532000Z", + "event_kind": "voice", + "forwarded_systems": ["OBP-USA"], + "frame_count": 36, + "is_proxy_ingress": false, + "is_synthetic": false, + "origin_system": "SYSTEM", + "peer_id": 312000, + "pkt_time": 1758229511.532, + "server_id": 73010, + "slot": 1, + "src_id": 7300391, + "started_at": "2026-09-18T21:05:09.372000Z", + "stream_id": 1234567890, + "system_mode": "MASTER" +} +``` + +Para sesiones unit-data, `event_kind` es `"unit_data"` y el campo de conteo es `packet_count` en vez de `frame_count`. Las patas que cruzaron un OpenBridge también llevan `obp_source_server_id`, `obp_hops`, `obp_source_rptr_id`, `ber`, `rssi` cuando aplica (ver [Tipos de evento](#tipos-de-evento) más arriba). + +Para probarlo de punta a punta: `enabled: true`, reload, haz una llamada o manda unit data a través del servidor, y revisa `example-events/.json` bajo el project root. Sus propios tests (`plugins/example/tests/`) cubren el tracking de sesión y la forma del JSON — ver [Tests](#tests) más abajo para correrlos. ---