diff --git a/docs/en/README.md b/docs/en/README.md index fa9ee37..1baeb9b 100644 --- a/docs/en/README.md +++ b/docs/en/README.md @@ -24,6 +24,7 @@ The **ADN DMR Peer Server** is a [GPL-3.0](https://www.gnu.org/licenses/gpl-3.0. | TG 4000, 999x, echo | [Special numbers](server/user-guide/special-numbers.md) | | Private calls | [Private calls](server/user-guide/private-calls.md) | | Voice / TTS | [Voice, announcements, and TTS](server/user-guide/voice-and-tts.md) | +| Legacy dashboard + server 2.x | [Report proxy](server/user-guide/report-proxy.md) | | OpenBridge / DMRE | [OpenBridge](server/protocols/openbridge.md), [DMRE v5](server/protocols/dmre-v5.md) | | HBP | [HBP](server/protocols/hbp.md) | | Code layout | [Architecture](server/development/architecture.md), [Behaviour and timers](server/development/behaviour-and-timers.md) | @@ -34,6 +35,7 @@ The **ADN DMR Peer Server** is a [GPL-3.0](https://www.gnu.org/licenses/gpl-3.0. ```bash pip install -r requirements.txt cp adn-server.example.yaml adn-server.yaml +# Edit DATABASE (MariaDB) and secrets before production start python adn-server.py -c adn-server.yaml ``` @@ -50,7 +52,7 @@ Dashboard, WebSocket live view, FastAPI API, **MySQL** self-service — see [Mon | `adn-server.yaml` — integrated `PROXY` / `SELF_SERVICE` | [Hotspot proxy (integrated)](server/user-guide/hotspot-proxy.md) | | `adn-monitor.yaml`, layout | [Monitor configuration](monitor/configuration.md) | | Integrated hotspot proxy | [Hotspot proxy](server/user-guide/hotspot-proxy.md) | -| Standalone hotspot proxy (UDP port range) | [Hotspot proxy — standalone](monitor/hotspot-proxy.md#standalone-proxy-legacy-adn-monitor-repo) | +| Standalone hotspot proxy (removed) | [Hotspot proxy — moved](monitor/hotspot-proxy.md) | | Self-service | [Self-service](monitor/self-service.md) | | How it connects to the server | [Monitoring and reports](server/user-guide/monitoring.md) | diff --git a/docs/en/monitor/configuration.md b/docs/en/monitor/configuration.md index b58ec03..b170b73 100644 --- a/docs/en/monitor/configuration.md +++ b/docs/en/monitor/configuration.md @@ -102,6 +102,18 @@ Obsolete **`WEBSOCKET_SERVER`** YAML (Twisted on a separate port) is ignored; us --- +## Database schema and migrations + +**adn-monitor** ships SQL migrations in `monitor/src/adn_monitor/infrastructure/persistence/schema.py`. Apply with **`db_bootstrap --update`** (or equivalent) when upgrading. + +| Migration | Table / change | +|-----------|----------------| +| **`004_peer_dynamic_tgs`** | **`peer_dynamic_tgs`** — per-peer dynamic TG rows written by **adn-server 2.0.0-rc.3+** (shared schema). | + +**adn-server** also ensures **`peer_dynamic_tgs`** exists on startup (idempotent). Either path is sufficient; both can run against the same **`hbmon`** database. + +--- + ## Environment - **`ADN_CONFIG_PATH`**: Absolute path to **`adn-monitor.yaml`** for **`monitor.py`**. diff --git a/docs/en/monitor/index.md b/docs/en/monitor/index.md index 77f827d..e97bdad 100644 --- a/docs/en/monitor/index.md +++ b/docs/en/monitor/index.md @@ -18,7 +18,9 @@ This chapter documents the **adn-monitor** stack at the same level of detail as | **`adn-server.yaml`** | **`adn-server.py`** (integrated **`PROXY`** / **`SELF_SERVICE`**) | `-c` / default path next to binary | | **`monitor/adn-monitor.yaml`** | **`monitor.py`** | **`ADN_CONFIG_PATH`** | -**`SELF_SERVICE`** (MySQL / PBKDF2) must **match** between **`adn-server.yaml`** and **`adn-monitor.yaml`**. **`ADN_CONNECTION`**, dashboard, WebSocket, and aliases live in **`adn-monitor.yaml`**; integrated **`PROXY`** lives in **`adn-server.yaml`** — see [Hotspot proxy (integrated)](../server/user-guide/hotspot-proxy.md). +**`SELF_SERVICE`** (MySQL / PBKDF2) must **match** between **`adn-server.yaml`** and **`adn-monitor.yaml`**. On the server, MariaDB credentials are in **`DATABASE`** (shared pool for self-service and **`peer_dynamic_tgs`**). **`ADN_CONNECTION`**, dashboard, WebSocket, and aliases live in **`adn-monitor.yaml`**; integrated **`PROXY`** lives in **`adn-server.yaml`** — see [Hotspot proxy (integrated)](../server/user-guide/hotspot-proxy.md). + +**Recommended pairing:** **adn-server 2.0.0-rc.3** + **adn-monitor 2.0.0-rc.4** (dynamic TG persistence, TG 4000 monitor sync). ## Link to the peer server diff --git a/docs/en/server/development/architecture.md b/docs/en/server/development/architecture.md index aa08227..e61068e 100644 --- a/docs/en/server/development/architecture.md +++ b/docs/en/server/development/architecture.md @@ -32,6 +32,7 @@ Wire opcodes and YAML keys may still say “bridge” for legacy monitor compati | Voice / TTS | `application/voice_use_cases.py`, `infrastructure/voice/` | | Hotspot proxy (fan-in) | `infrastructure/proxy/` (`udp_fanin.py`, `runtime.py`), `application/proxy/` use cases | | Self-service (MySQL) | `infrastructure/proxy/self_service_bridge.py`, `infrastructure/proxy/persistence/` | +| Dynamic TG persistence | `application/dynamic_tg_use_cases.py`, `infrastructure/persistence/dynamic_tg_repository.py`, `application/routing/dynamic_tg_restore.py` | ## Configuration as shared state diff --git a/docs/en/server/development/behaviour-and-timers.md b/docs/en/server/development/behaviour-and-timers.md index 182d359..16af023 100644 --- a/docs/en/server/development/behaviour-and-timers.md +++ b/docs/en/server/development/behaviour-and-timers.md @@ -20,6 +20,7 @@ The following intervals are part of the current runtime behavior: | `stream_trimmer` | **5s** | Stream cleanup, timeout handling, end-of-call state trimming. | | `bridge_reset` | **6s** | Bridge reset flag cleanup and pending reset completion. | | OPTIONS refresh | **event-driven** | Static TG / reflector from **RPTO**, **startup/reload** (`apply_startup_bridges`), **dmrd** no-source fallback. No periodic 26s loop (**D-28**). | +| `dynamic_tg_purge_loop` | **60s** | Purge expired **SINGLE=1** rows from `peer_dynamic_tgs` and in-memory `_PEER_UA_SESSIONS`. | | `statTrimmer` | **303s** | Trim stale STAT bridges and transient status entries. | If you change one of these intervals, document the operational impact for monitoring, loop behavior, and troubleshooting. diff --git a/docs/en/server/user-guide/bridges-and-talkgroups.md b/docs/en/server/user-guide/bridges-and-talkgroups.md index cfbc2bb..af8230b 100644 --- a/docs/en/server/user-guide/bridges-and-talkgroups.md +++ b/docs/en/server/user-guide/bridges-and-talkgroups.md @@ -17,6 +17,30 @@ The router scans `BRIDGES` for an **ACTIVE** row matching the **current source s - **User-activated** bridges are created when a user keys a TG without a pre-built row (subject to `DEFAULT_UA_TIMER` and options). - **Static** TGs and **STAT** bridges are created from **OPTIONS** / `make_static_tg` / `GEN_STAT_BRIDGES` flows. +## Dynamic TG persistence (MariaDB) {#dynamic-tg-persistence-mariadb} + +Since **2.0.0-rc.3**, user-activated dynamic TGs for each hotspot can be **persisted in MariaDB** (`peer_dynamic_tgs`) so they survive **hotspot disconnect/reconnect** without re-keying the TG. + +| Event | Server behaviour | +|-------|------------------| +| **Group voice header** (new dynamic TG on a slot) | Registers UA session in memory and **async upsert** to `peer_dynamic_tgs`. | +| **RPTC** (hotspot login OK) | **Restores** rows for that peer/system into memory and re-syncs bridge rows (`ensure_dynamic_relay`). | +| **TG 4000** | Clears **all** dynamic slots for that peer (memory + DB). See [Special numbers — TG 4000](special-numbers.md#tg--id-4000--deactivate-dynamic-bridges). | +| **Hotspot disconnect** | Clears per-peer **mirror** state only; persisted rows and global `_PEER_UA_*` maps are kept until expiry or TG 4000. | +| **Periodic purge** | Every **60 s**, expired **SINGLE=1** rows are removed from DB and memory. | + +**SINGLE=0** peers accumulate several dynamic TGs per slot in memory (`_PEER_UA_MULTI_TGS`). **SINGLE=1** stores one exclusive TG per slot with a timer. + +**TG 4000** is never stored as a dynamic session (reset command only). + +Requires **`DATABASE`** in `adn-server.yaml` — see [Configuration](configuration.md#database-mariadb). + +## Cross-slot static TG downlink (inject-only) + +On **inject-only** MASTER systems (integrated **`PROXY`**), group voice downlink respects **static TGs listed in either TS1 or TS2 OPTIONS**, even when the **wire timeslot** differs. This matches legacy REPEAT behaviour for hotspots that list a TG on one slot but transmit on another. + +The server does **not** rewrite the incoming DMRD slot; it filters **which peers receive** the repeated packet via `peer_should_receive_group_voice` and the downlink index. + ## Source-row guard and safe iteration Forwarding is allowed only when the current system has a matching **ACTIVE source row** for that TG/slot context. This prevents accidental forwarding from rows that are present but not currently eligible as source legs. diff --git a/docs/en/server/user-guide/configuration.md b/docs/en/server/user-guide/configuration.md index 143fc8a..728b7c8 100644 --- a/docs/en/server/user-guide/configuration.md +++ b/docs/en/server/user-guide/configuration.md @@ -29,9 +29,9 @@ kill -HUP $(pidof adn-server.py) # or: systemctl reload adn-server Example unit: **`examples/systemd/adn-server.service`** (copy to `/etc/systemd/system/`; includes `ExecReload` for `systemctl reload`). -**Reload applies:** `GLOBAL`, `REPORTS`, `ALIASES`, **`LOGGER.LOG_LEVEL`** (without process restart), **`PROXY`** (timeouts, debug, block lists — not bind or target), **`SELF_SERVICE`** (merged; enabling/disabling DB loops needs restart), per-system settings, **new/removed SYSTEMS** (including `GENERATOR` expansion/collapse and new OpenBridge legs), and updated bind addresses (listener restart for that system only). +**Reload applies:** `GLOBAL`, `REPORTS`, `ALIASES`, **`LOGGER.LOG_LEVEL`** (without process restart), **`PROXY`** (timeouts, debug, block lists — not bind or target), **`SELF_SERVICE`** (PBKDF2 flags merged; enabling/disabling DB loops needs restart), per-system settings, **new/removed SYSTEMS** (including `GENERATOR` expansion/collapse and new OpenBridge legs), and updated bind addresses (listener restart for that system only). -**Not reloaded:** `adn-voice.yaml` (separate 15 s loop), Python code, subscriber alias files (separate periodic reload). **BRIDGES** table is not rebuilt on reload — restart if bridge rules changed in a way that requires a full reset. **`PROXY.LISTEN_PORT`**, **`LISTEN_IP`**, and **`TARGET_SYSTEM`** require a **full restart** to take effect. +**Not reloaded:** **`DATABASE`** (MariaDB pool and `peer_dynamic_tgs` bootstrap), `adn-voice.yaml` (separate 15 s loop), Python code, subscriber alias files (separate periodic reload). **BRIDGES** table is not rebuilt on reload — restart if bridge rules changed in a way that requires a full reset. **`PROXY.LISTEN_PORT`**, **`LISTEN_IP`**, and **`TARGET_SYSTEM`** require a **full restart** to take effect. **Secrets:** Never commit real passphrases, security URLs, or `user_passwords.json` / `encryption_key.secret`. Use placeholders in templates and keep production files local. @@ -169,7 +169,7 @@ For the conceptual model (ACTIVE, TS, TGID, timeouts): [Bridges and talkgroups]( ## `REPORTS` -TCP report channel for **adn-monitor** (or compatible dashboards). +TCP report channel for **adn-monitor** (or compatible dashboards). **adn-server 2.x** speaks **report v2** only; legacy dashboards that expect **v1** need the optional [report-proxy](report-proxy.md) (separate package). | Key | Meaning | |-----|---------| @@ -178,7 +178,7 @@ TCP report channel for **adn-monitor** (or compatible dashboards). | **REPORT_PORT** | Local port the **server listens on** for report clients. | | **REPORT_CLIENTS** | Comma-separated or list of allowed client IPs (see example). | -Details: [Monitoring and reports](monitoring.md). +Details: [Monitoring and reports](monitoring.md). Legacy v1 monitors: [Report proxy](report-proxy.md). --- @@ -198,9 +198,38 @@ Do **not** run standalone **`adn-proxy`** on the same **`LISTEN_PORT`** when the --- +## `DATABASE` (MariaDB) + +**Required** for typical conference-server configs: any deployment with **`PROXY`**, or at least one **`MASTER`** / **`OPENBRIDGE`** system. **Not** required for minimal **echo-only** PEER fleets (`adn-server.py --echo`). + +| Key | Meaning | +|-----|---------| +| **DB_SERVER** | MariaDB/MySQL host. | +| **DB_USERNAME** / **DB_PASSWORD** | Credentials. | +| **DB_NAME** | Database name (often the same as **adn-monitor**, e.g. `hbmon`). | +| **DB_PORT** | TCP port (default **3306**). | + +**Uses one shared connection pool** for: + +- **Dynamic TG persistence** — table **`peer_dynamic_tgs`** (per-peer user-activated TGs across hotspot reconnects). The server **creates the table on startup** if missing (migration id **`004_peer_dynamic_tgs`**, same schema as adn-monitor). +- **Integrated self-service** — table **`Clients`** when **`SELF_SERVICE.USE_SELFSERVICE: true`**. + +Startup aborts with a clear log if MariaDB is unreachable or **`DATABASE`** is incomplete. Install **`mysqlclient`** (`pip install -e ".[selfservice]"` includes it). + +**Hot reload:** changing **`DATABASE`** requires a **full process restart**. + +Details: [Bridges and talkgroups — dynamic TG persistence](bridges-and-talkgroups.md#dynamic-tg-persistence-mariadb). + +--- + ## `SELF_SERVICE` (MySQL / dashboard options) -Optional; requires `pip install -e ".[selfservice]"` when **`USE_SELFSERVICE: true`**. Uses the same **`Clients`** table and PBKDF2 parameters as **adn-monitor**. Keys match the monitor docs — see [Self-service](../../monitor/self-service.md) and [Hotspot proxy](hotspot-proxy.md#self_service-keys). +Optional; requires `pip install -e ".[selfservice]"` when **`USE_SELFSERVICE: true`**. Uses the **`DATABASE`** block above (not separate DB keys in **`SELF_SERVICE`**). PBKDF2 parameters must **match** **adn-monitor**. See [Self-service](../../monitor/self-service.md) and [Hotspot proxy](hotspot-proxy.md#self_service-keys). + +| Key | Meaning | +|-----|---------| +| **USE_SELFSERVICE** | Enable MySQL-backed options sync from the dashboard (`true` / `false`). | +| **PBKDF2_SALT** / **PBKDF2_ITERATIONS** | Must match **`adn-monitor.yaml`** / password tooling. | --- diff --git a/docs/en/server/user-guide/hotspot-proxy.md b/docs/en/server/user-guide/hotspot-proxy.md index 0acc149..12231e8 100644 --- a/docs/en/server/user-guide/hotspot-proxy.md +++ b/docs/en/server/user-guide/hotspot-proxy.md @@ -72,9 +72,10 @@ Same semantics as **`adn-monitor.yaml`** — shared **`Clients`** table, **`modi | Key | Role | |-----|------| | **USE_SELFSERVICE** | Enable MySQL-backed options sync (`true` / `false`). | -| **DB_SERVER**, **DB_USERNAME**, **DB_PASSWORD**, **DB_NAME**, **DB_PORT** | MySQL connection. | | **PBKDF2_SALT**, **PBKDF2_ITERATIONS** | Must **match** monitor/backend for password hashing. | +MariaDB connection settings live in the top-level **`DATABASE`** block (shared with dynamic TG persistence) — see [Configuration](configuration.md#database-mariadb). + On startup the server logs **`(SELF_SERVICE) Database connection test: OK`** and **`(SELF_SERVICE) Enabled`** when the pool connects. Self-service runs **asynchronously**; voice forwarding is not blocked on DB latency. Details of the dashboard flow: [Self-service](../../monitor/self-service.md). diff --git a/docs/en/server/user-guide/introduction.md b/docs/en/server/user-guide/introduction.md index 4fa25f5..efc38bf 100644 --- a/docs/en/server/user-guide/introduction.md +++ b/docs/en/server/user-guide/introduction.md @@ -17,8 +17,8 @@ Routing, timers, OpenBridge loop control, and protocol handling are implemented | Subsystem | Role | |-----------|------| -| **Bridge router** | `BRIDGES` table: which systems forward which TG on which slot; dynamic bridges; static/stat bridges. | -| **HBP protocol** | Authentication, DMRD ingress/egress, repeat to peers, TG filters. | +| **Bridge router** | `BRIDGES` table: which systems forward which TG on which slot; dynamic bridges; static/stat bridges; **MariaDB dynamic TG restore** on reconnect. | +| **HBP protocol** | Authentication, DMRD ingress/egress, repeat to peers, TG filters, **per-peer UA session** tracking. | | **OpenBridge** | DMRE ingress, hop limit, loop control (`min(1ST)`), BCSQ/BCKA when enabled. | | **Voice** | AMBE files, scheduled announcements, TTS pipeline, on-demand playback (TG 9991–9999). | | **Reporting** | TCP netstring channel to **adn-monitor** (and compatible dashboards): config, bridge state, call events (report v2 JSON). | @@ -28,10 +28,11 @@ Routing, timers, OpenBridge loop control, and protocol handling are implemented - **Echo / playback** — `adn-server.py --echo` with minimal `adn-echo.yaml`; see [Echo](echo.md). - **Integrated hotspot proxy** — `PROXY` in **`adn-server.yaml`**; see [Hotspot proxy](hotspot-proxy.md). +- **Report proxy (legacy dashboards)** — optional **[ADN-report-proxy](https://github.com/ce5rpy/ADN-report-proxy)** so **adn-server 2.x** can feed old HBMonitor / FDMR-style monitors (v1 wire); see [Report proxy](report-proxy.md). Not used with **adn-monitor 2.x**. ## Next steps -- [Configuration](configuration.md) — files, `GLOBAL`, **MASTER** / **PEER** / **OPENBRIDGE**, ACLs, reports, **`PROXY`**, **`SELF_SERVICE`**, aliases, voice merge. +- [Configuration](configuration.md) — files, `GLOBAL`, **MASTER** / **PEER** / **OPENBRIDGE**, ACLs, **`DATABASE`**, reports, **`PROXY`**, **`SELF_SERVICE`**, aliases, voice merge. - [Bridges and talkgroups](bridges-and-talkgroups.md) — how `BRIDGES` works. - [Special numbers](special-numbers.md) — TG 4000, information services, echo. - [Hotspot proxy](hotspot-proxy.md) — integrated **`PROXY`** / **`SELF_SERVICE`** in `adn-server.yaml`. diff --git a/docs/en/server/user-guide/monitoring.md b/docs/en/server/user-guide/monitoring.md index fa7390f..d45a460 100644 --- a/docs/en/server/user-guide/monitoring.md +++ b/docs/en/server/user-guide/monitoring.md @@ -12,6 +12,12 @@ When **`REPORTS`** is enabled in the server config, the **ADN DMR Peer Server** **Version pairing:** **server 1.0.x + monitor 1.0.x** = report v1 (frozen tags). **server 2.x** emits **report v2 only** — requires **monitor 2.x** on the same line. No `dual` wire; monitor 1.0.x will not decode this server. +### Legacy dashboards (report-proxy) + +If you keep an **old dashboard** whose backend monitor speaks **report v1** only (pickle/CSV, no HELLO v2), it **cannot** connect to **adn-server 2.x** on `REPORTS.REPORT_PORT`. Use the optional **[ADN-report-proxy](https://github.com/ce5rpy/ADN-report-proxy)** to translate **v2 → v1**: the proxy connects to the server; the legacy monitor connects to the proxy. **adn-monitor 2.x** does **not** need this proxy — connect it directly to the server. + +See [Report proxy (legacy dashboards)](report-proxy.md) for topology, `REPORT_CLIENTS`, ports, and start order. + Older stacks (**legacy** `adn-dmr-server`-style) may **omit** HELLO. **adn-monitor** waits up to **`ADN_CONNECTION.HELLO_TIMEOUT_MS`** (see [Monitor configuration](../../monitor/configuration.md#adn_connection)); if no HELLO arrives, it assumes **legacy** reporting. The **monitor** decodes these messages, updates its **CTABLE** / **BTABLE**, and (when MySQL is configured) persists Last Heard / statistics. @@ -40,6 +46,19 @@ At **WARNING**: invalid HELLO JSON (`(REPORT) HELLO payload not valid JSON`), or The dashboard shows **operational** state from **START** (canonical); the **Monitor** log shows **INGRESS** plus **START** for troubleshooting mesh duplicates. +### Dynamic UA chips (hotspot OPTIONS) + +The monitor tracks **user-activated** TGs per hotspot for dashboard indigo chips: + +| Peer OPTIONS | Monitor source | +|--------------|----------------| +| **SINGLE=1** | **`UA_SESSIONS`** in **CONFIG_SND** / `dashboard_state` (server source of truth). | +| **SINGLE=0** | Voice events (`BRDG_EVENT` / `voice_event`) — multiple dynamics per slot until cleared. | + +**TG 4000** clears UA state via **`GROUP VOICE,INGRESS,RX`** with destination **4000** (server sends this because the voice path returns early and never emits a normal **START**). The monitor must **not** register **4000** as a dynamic TG. + +**Version pairing:** **adn-server 2.0.0-rc.3** + **adn-monitor 2.0.0-rc.4** for dynamic TG persistence and TG 4000 monitor sync. + ## Log file rotation (logrotate) After **logrotate** renames or moves a log file (common pattern: **`create`** so the old path is rotated away and a **new empty file** appears at the configured path), the process may still hold an open file descriptor on the **previous inode**. Logs then appear “missing” from the current path until the process **reopens** its file handlers. diff --git a/docs/en/server/user-guide/report-proxy.md b/docs/en/server/user-guide/report-proxy.md new file mode 100644 index 0000000..2a7a403 --- /dev/null +++ b/docs/en/server/user-guide/report-proxy.md @@ -0,0 +1,100 @@ +# Report proxy (legacy dashboards) + +**ADN DMR Peer Server 2.x** emits **report wire v2** (JSON over TCP). **adn-monitor 2.x** understands that protocol and connects **directly** to the server — no extra component is required. + +Some **legacy dashboard stacks** still ship their own `dashboard.py` / `monitor.py` backend and speak **report wire v1** only (pickled `CONFIG_SND` / `BRIDGE_SND`, CSV `BRDG_EVENT`). Those monitors **cannot** connect to **adn-server 2.x** on the report port. + +The optional **[ADN-report-proxy](https://github.com/ce5rpy/ADN-report-proxy)** package sits between the two: it connects **upstream** to the real server (v2), listens **downstream** where the legacy monitor expects the server (v1), and translates **v2 → v1**. + +| Stack | Upstream server | Works without proxy? | +|-------|-----------------|----------------------| +| **adn-monitor 2.x** (React) | **adn-server 2.x** | Yes — connect to `REPORTS.REPORT_PORT` | +| Legacy dashboard + bundled monitor (v1) | **adn-dmr-server** (v1) | Yes — direct to server report port | +| Legacy dashboard + bundled monitor (v1) | **adn-server 2.x** (v2) | **No** — use **report-proxy** | + +Typical legacy targets: old **ADN-Dashboard** forks, **HBMonitor** / **FDMR Monitor** deployments that still run a Python monitor process against `dashboard.cfg` / `monitor.cfg`. + +## Topology + +```text +┌───────────────────┐ +│ adn-server │ +│ LISTENS :4321 │ +└─────────▲─────────┘ + │ + │ TCP v2 JSON + │ (report-proxy is CLIENT) + │ +┌─────────┴─────────┐ +│ report-proxy │ +│ LISTENS :4322 │ +└─────────▲─────────┘ + │ + │ TCP v1 pickle + │ (legacy dashboard is CLIENT) + │ +┌─────────┴─────────┐ +│ legacy dashboard │ +│ monitor.py │ +└───────────────────┘ +``` + +| Component | Role | Default port | Config | Key setting | +|-----------|------|--------------|--------|-------------| +| **adn-server** | Listens for report clients | **4321** | `adn-server.yaml` | `REPORTS.REPORT_PORT` | +| **report-proxy** | Connects to the server | 4321 | `report-proxy.yaml` | `UPSTREAM.PORT` | +| **report-proxy** | Listens for the legacy monitor | **4322** | `report-proxy.yaml` | `LISTEN.PORT` | +| **Legacy dashboard** | Connects to the proxy | **4322** | `dashboard.cfg` | `SERVER_PORT` | + +**Do not** point the legacy dashboard at **4321** — that is the server’s v2 port. + +**Do not** set `UPSTREAM.PORT` to **4322** — that is the proxy’s own listen port. + +## Server side (`adn-server.yaml`) + +Reporting must be enabled and the **proxy host IP** must be in the allow list: + +```yaml +REPORTS: + REPORT: true + REPORT_INTERVAL: 60 + REPORT_PORT: 4321 + REPORT_CLIENTS: "127.0.0.1" # IP of the machine running report-proxy +``` + +If the proxy runs on another host, use **that host’s IP** in `REPORT_CLIENTS`, not only `127.0.0.1`. See [Configuration](configuration.md#reports) for all `REPORTS` keys. + +## Proxy and legacy dashboard + +Install and run the proxy from the **[ADN-report-proxy](https://github.com/ce5rpy/ADN-report-proxy)** repository (`report-proxy.yaml`, `python3 report-proxy.py -c report-proxy.yaml`). Point `UPSTREAM` at the server’s `REPORT_PORT` and `LISTEN` at the port the legacy monitor uses (often **4322**). + +In legacy `dashboard.cfg` / `monitor.cfg`: + +```ini +[SERVER CONNECTION] +SERVER_IP = 127.0.0.1 +SERVER_PORT = 4322 +``` + +`SERVER_IP` is the host where **report-proxy** listens, not necessarily the adn-server host. + +**Start order:** adn-server → report-proxy → legacy monitor backend. + +Full step-by-step, multi-host examples, verification checks, and common mistakes: **[ADN-report-proxy README](https://github.com/ce5rpy/ADN-report-proxy#configuration-legacy-dashboard--adn-server-2x)**. + +## Wire translation (summary) + +| Upstream (v2 from adn-server) | Downstream (v1 to legacy monitor) | +|--------------------------------|-----------------------------------| +| `HELLO` (`report_protocol: 2`) | `HELLO` (`protocol: 1`) | +| `STATE_SND` / `dashboard_state` | `CONFIG_SND` (pickle) | +| `ROUTING_TABLE_SND` | `BRIDGE_SND` (pickle) | +| `TOPOLOGY_SND` | `CONFIG_SND` (pickle) | +| `VOICE_EVENT_SND` | `BRDG_EVENT` (CSV) | + +Schema detail for v2: [Report protocol v2 (JSON)](../protocols/report-v2.md). + +## See also + +- [Monitoring and reports](monitoring.md) — report channel, **adn-monitor** pairing, log lines. +- [ADN Monitor overview](../../monitor/index.md) — preferred dashboard for **adn-server 2.x** (no proxy). diff --git a/docs/en/server/user-guide/special-numbers.md b/docs/en/server/user-guide/special-numbers.md index 3f70ec1..e6b5725 100644 --- a/docs/en/server/user-guide/special-numbers.md +++ b/docs/en/server/user-guide/special-numbers.md @@ -56,19 +56,24 @@ In-band bridge activation/deactivation is applied on **voice terminator (VTERM)* - For reflector bridges (`#...`), in-band handling is evaluated only when the destination is **TG 9**. - This is why reflector prompts and dial wiring are tied to TG 9 while private calls do not trigger that bridge-timer logic. -## TG / ID 4000 — deactivate dynamic bridges +## TG / ID 4000 — deactivate dynamic bridges {#tg--id-4000--deactivate-dynamic-bridges} -**Purpose:** Clear **user-activated (dynamic) bridges** for the system that receives the call. +**Purpose:** Clear **user-activated (dynamic)** state for the hotspot that keys **4000**. **TG 4000 is not** a talkgroup to monitor or persist — it is a **reset command**. -**Behaviour:** +**Behaviour (group voice header):** + +- Clears per-peer UA sessions in memory (**all slots** for that peer). +- Deletes matching rows from **`peer_dynamic_tgs`** (MariaDB). +- Clears stale **STATUS** RX fields so a later **RPTO** does not re-seed the old TG. +- Runs **in-band bridge deactivation** on the slot (same as legacy). +- Sends **`GROUP VOICE,INGRESS,RX,…,4000`** to the monitor (not **START**) so **SINGLE=0** multi-dynamic chips clear **without** lighting a live TX chip. +- On **inject-only** MASTER, pushes updated **CONFIG_SND** to the monitor. -- Implemented for **group** traffic to destination **4000** (and related checks in the router). -- Runs **before** normal TG ACL in the OpenBridge path so the command is not blocked by allow lists. -- Invokes **`deactivate_all_dynamic_bridges`**: deactivates non-stat, non-reflector dynamic bridge rows. +**Inject-only vs global:** With integrated **`PROXY`**, reset is **per peer** (only that hotspot’s dynamics). Without inject-only filtering, legacy **`deactivate_all_dynamic_bridges`** still runs for the whole system. -Use this when operators need to **reset** dynamic routing without restarting the server. +**TG 4000 must never appear** as a dynamic UA chip on the monitor or in `peer_dynamic_tgs`. -### `SINGLE_MODE` impact on deactivation logic +### `SINGLE_MODE` impact on in-band deactivation When in-band rules evaluate deactivation on a MASTER slot: diff --git a/docs/es/README.md b/docs/es/README.md index aec91d2..8e1b060 100644 --- a/docs/es/README.md +++ b/docs/es/README.md @@ -23,6 +23,7 @@ El **ADN DMR Peer Server** es un puente de conferencia [GPL-3.0](https://www.gnu | TG 4000, 999x, eco | [Números especiales](server/user-guide/special-numbers.md) | | Llamadas privadas | [Llamadas privadas](server/user-guide/private-calls.md) | | Voz / TTS | [Voz, anuncios y TTS](server/user-guide/voice-and-tts.md) | +| Panel legacy + servidor 2.x | [Proxy de informes](server/user-guide/report-proxy.md) | | OpenBridge / DMRE | [OpenBridge](server/protocols/openbridge.md), [DMRE v5](server/protocols/dmre-v5.md) | | HBP | [HBP](server/protocols/hbp.md) | | Código | [Arquitectura](server/development/architecture.md), [Comportamiento y temporizadores](server/development/behaviour-and-timers.md) | @@ -33,6 +34,7 @@ El **ADN DMR Peer Server** es un puente de conferencia [GPL-3.0](https://www.gnu ```bash pip install -r requirements.txt cp adn-server.example.yaml adn-server.yaml +# Edita DATABASE (MariaDB) y secretos antes de producción python adn-server.py -c adn-server.yaml ``` diff --git a/docs/es/monitor/configuration.md b/docs/es/monitor/configuration.md index 8e76741..55906ed 100644 --- a/docs/es/monitor/configuration.md +++ b/docs/es/monitor/configuration.md @@ -120,7 +120,9 @@ No hay Alembic: el monitor usa **`schema_migrations`** y comprobaciones en **`in - **Replace:** carga en `{tabla}_import` con **commit cada 10 000 filas** (la tabla live sigue legible); swap atómico `RENAME TABLE` (bloqueo metadata breve). - **Merge** (ficheros locales): `INSERT IGNORE` con **commit cada 2 000 filas**. -Migraciones: `001_clients_callsign`, `002_clients_options_width`, `003_alias_pk_only`. +Migraciones: `001_clients_callsign`, `002_clients_options_width`, `003_alias_pk_only`, **`004_peer_dynamic_tgs`** (tabla compartida con **adn-server 2.0.0-rc.3+**). + +**adn-server** también asegura **`peer_dynamic_tgs`** al arrancar (idempotente). Cualquiera de los dos caminos basta; ambos pueden usar la misma base **`hbmon`**. --- diff --git a/docs/es/monitor/index.md b/docs/es/monitor/index.md index 42f9dd1..a989b1f 100644 --- a/docs/es/monitor/index.md +++ b/docs/es/monitor/index.md @@ -18,7 +18,9 @@ Este capítulo documenta la pila **adn-monitor** con el mismo nivel de detalle q | **`adn-server.yaml`** | **`adn-server.py`** (**`PROXY`** / **`SELF_SERVICE`** integrados) | `-c` / ruta por defecto junto al binario | | **`monitor/adn-monitor.yaml`** | **`monitor.py`** | **`ADN_CONFIG_PATH`** | -**`SELF_SERVICE`** (MySQL / PBKDF2) debe **coincidir** entre **`adn-server.yaml`** y **`adn-monitor.yaml`**. **`ADN_CONNECTION`**, panel, WebSocket y alias van en **`adn-monitor.yaml`**; **`PROXY`** integrado va en **`adn-server.yaml`** — ver [Proxy hotspot integrado](../server/user-guide/hotspot-proxy.md). +**`SELF_SERVICE`** (MySQL / PBKDF2) debe **coincidir** entre **`adn-server.yaml`** y **`adn-monitor.yaml`**. En el servidor, las credenciales MariaDB van en **`DATABASE`** (pool compartido con **`peer_dynamic_tgs`**). **`ADN_CONNECTION`**, panel, WebSocket y alias van en **`adn-monitor.yaml`**; **`PROXY`** integrado va en **`adn-server.yaml`** — ver [Proxy hotspot integrado](../server/user-guide/hotspot-proxy.md). + +**Emparejamiento recomendado:** **adn-server 2.0.0-rc.3** + **adn-monitor 2.0.0-rc.4** (persistencia TG dinámicos, sincronización TG 4000 en monitor). ## Enlace con el peer server diff --git a/docs/es/server/development/architecture.md b/docs/es/server/development/architecture.md index 6190812..f628851 100644 --- a/docs/es/server/development/architecture.md +++ b/docs/es/server/development/architecture.md @@ -32,6 +32,7 @@ Los opcodes wire y claves YAML pueden seguir diciendo “bridge” por compatibi | Voz / TTS | `application/voice_use_cases.py`, `infrastructure/voice/` | | Proxy hotspot (fan-in) | `infrastructure/proxy/` (`udp_fanin.py`, `runtime.py`), casos de uso en `application/proxy/` | | Self-service (MySQL) | `infrastructure/proxy/self_service_bridge.py`, `infrastructure/proxy/persistence/` | +| Persistencia TG dinámicos | `application/dynamic_tg_use_cases.py`, `infrastructure/persistence/dynamic_tg_repository.py`, `application/routing/dynamic_tg_restore.py` | ## Configuración como estado compartido diff --git a/docs/es/server/development/behaviour-and-timers.md b/docs/es/server/development/behaviour-and-timers.md index b303041..314098c 100644 --- a/docs/es/server/development/behaviour-and-timers.md +++ b/docs/es/server/development/behaviour-and-timers.md @@ -20,6 +20,7 @@ Los siguientes intervalos forman parte del comportamiento actual en ejecución: | `stream_trimmer` | **5s** | Limpieza de streams, manejo de timeout y cierre de estado de llamada. | | `bridge_reset` | **6s** | Limpieza de flags de reset y cierre de resets pendientes. | | OPTIONS refresh | **por evento** | TG estáticas / reflector vía **RPTO**, **startup/reload** (`apply_startup_bridges`), fallback **dmrd** sin source. Sin loop periódico de 26s (**D-28**). | +| `dynamic_tg_purge_loop` | **60s** | Purga filas **SINGLE=1** expiradas de `peer_dynamic_tgs` y `_PEER_UA_SESSIONS` en memoria. | | `statTrimmer` | **303s** | Limpieza de bridges STAT obsoletos y estados transitorios. | Si cambias uno de estos intervalos, documenta el impacto operativo en monitorización, comportamiento de bucles y troubleshooting. diff --git a/docs/es/server/user-guide/bridges-and-talkgroups.md b/docs/es/server/user-guide/bridges-and-talkgroups.md index afda545..a56400d 100644 --- a/docs/es/server/user-guide/bridges-and-talkgroups.md +++ b/docs/es/server/user-guide/bridges-and-talkgroups.md @@ -17,6 +17,30 @@ El router recorre `BRIDGES` buscando una fila **ACTIVE** que coincida con el **s - Los bridges **activados por usuario** se crean cuando alguien pulsa una TG sin fila previa (sujeto a `DEFAULT_UA_TIMER` y opciones). - Las TG **estáticas** y bridges **STAT** se crean desde flujos **OPTIONS** / `make_static_tg` / `GEN_STAT_BRIDGES`. +## Persistencia TG dinámicos (MariaDB) {#persistencia-tg-dinamicos-mariadb} + +Desde **2.0.0-rc.3**, los TG dinámicos activados por usuario de cada hotspot pueden **persistirse en MariaDB** (`peer_dynamic_tgs`) para sobrevivir a **desconexión/reconexión** sin volver a pulsar el TG. + +| Evento | Comportamiento del servidor | +|--------|----------------------------| +| **Cabecera de voz de grupo** (nuevo TG dinámico en un slot) | Registra sesión UA en memoria y **upsert asíncrono** en `peer_dynamic_tgs`. | +| **RPTC** (login OK del hotspot) | **Restaura** filas de ese peer/system en memoria y re-sincroniza bridges (`ensure_dynamic_relay`). | +| **TG 4000** | Borra **todos** los slots dinámicos de ese peer (memoria + BD). Ver [Números especiales — TG 4000](special-numbers.md#tg--id-4000--desactivar-bridges-dinamicos). | +| **Desconexión del hotspot** | Solo limpia el **espejo** por peer; las filas persistidas y mapas globales `_PEER_UA_*` se mantienen hasta expiración o TG 4000. | +| **Purga periódica** | Cada **60 s**, filas **SINGLE=1** expiradas se eliminan de BD y memoria. | + +Peers **SINGLE=0** acumulan varios TG dinámicos por slot (`_PEER_UA_MULTI_TGS`). **SINGLE=1** guarda un TG exclusivo por slot con temporizador. + +**TG 4000** nunca se almacena como sesión dinámica (solo comando de reset). + +Requiere **`DATABASE`** en `adn-server.yaml` — ver [Configuración](configuration.md#database-mariadb). + +## Downlink cross-slot de TG estáticas (inject-only) + +En MASTER **inject-only** ( **`PROXY`** integrado), el downlink de voz de grupo respeta **TG estáticas listadas en OPTIONS de TS1 o TS2**, aunque el **slot en cable** sea otro. Equivale al comportamiento legacy REPEAT para hotspots que listan un TG en un slot y transmiten en otro. + +El servidor **no** reescribe el slot del DMRD entrante; filtra **a qué peers reenvía** el paquete repetido con `peer_should_receive_group_voice` y el índice de downlink. + ## Guardia de fila de origen e iteración segura El reenvío solo se permite cuando el sistema actual tiene una **fila de origen ACTIVE** que coincide con ese contexto TG/slot. Esto evita reenviar desde filas presentes pero no elegibles como patas de origen. diff --git a/docs/es/server/user-guide/configuration.md b/docs/es/server/user-guide/configuration.md index 7262cce..c1041df 100644 --- a/docs/es/server/user-guide/configuration.md +++ b/docs/es/server/user-guide/configuration.md @@ -29,9 +29,9 @@ kill -HUP $(pidof adn-server.py) # o: systemctl reload adn-server Unidad de ejemplo: **`examples/systemd/adn-server.service`** (copiar a `/etc/systemd/system/`; incluye `ExecReload` para `systemctl reload`). -**Se recarga:** `GLOBAL`, `REPORTS`, `ALIASES`, **`LOGGER.LOG_LEVEL`** (sin reiniciar el proceso), **`PROXY`** (timeouts, debug, listas de bloqueo — no bind ni destino), **`SELF_SERVICE`** (fusionado; activar/desactivar bucles BD requiere reinicio), parámetros por system, **systems nuevos/eliminados** (incluida expansión/colapso `GENERATOR` y OBP nuevos), y cambios de IP/puerto (solo reinicia el listener de ese system). +**Se recarga:** `GLOBAL`, `REPORTS`, `ALIASES`, **`LOGGER.LOG_LEVEL`** (sin reiniciar el proceso), **`PROXY`** (timeouts, debug, listas de bloqueo — no bind ni destino), **`SELF_SERVICE`** (flags PBKDF2 fusionados; activar/desactivar bucles BD requiere reinicio), parámetros por system, **systems nuevos/eliminados** (incluida expansión/colapso `GENERATOR` y OBP nuevos), y cambios de IP/puerto (solo reinicia el listener de ese system). -**No se recarga:** `adn-voice.yaml` (loop aparte cada 15 s), código Python, ficheros de alias (recarga periódica). La tabla **BRIDGES** no se reconstruye — reinicia si cambiaste reglas de bridge que exijan reset completo. **`PROXY.LISTEN_PORT`**, **`LISTEN_IP`** y **`TARGET_SYSTEM`** requieren **reinicio completo** para aplicarse. +**No se recarga:** **`DATABASE`** (pool MariaDB y bootstrap `peer_dynamic_tgs`), `adn-voice.yaml` (loop aparte cada 15 s), código Python, ficheros de alias (recarga periódica). La tabla **BRIDGES** no se reconstruye — reinicia si cambiaste reglas de bridge que exijan reset completo. **`PROXY.LISTEN_PORT`**, **`LISTEN_IP`** y **`TARGET_SYSTEM`** requieren **reinicio completo** para aplicarse. **Secretos:** no versionar passphrases reales, URLs de seguridad ni `user_passwords.json` / `encryption_key.secret`. Usa placeholders en plantillas y mantén producción en local. @@ -169,7 +169,7 @@ Para el modelo conceptual (ACTIVE, TS, TGID, timeouts): [Bridges y talkgroups](b ## `REPORTS` -Canal TCP de informes para **adn-monitor** (o paneles compatibles). +Canal TCP de informes para **adn-monitor** (o paneles compatibles). **adn-server 2.x** habla **solo informe v2**; los paneles legacy que esperan **v1** necesitan el opcional [report-proxy](report-proxy.md) (paquete aparte). | Clave | Significado | |-------|-------------| @@ -178,7 +178,7 @@ Canal TCP de informes para **adn-monitor** (o paneles compatibles). | **REPORT_PORT** | Puerto local en el que el **servidor escucha** clientes de informes. | | **REPORT_CLIENTS** | Lista separada por comas o lista de IPs de clientes permitidos (ver ejemplo). | -Detalle: [Monitor e informes](monitoring.md). +Detalle: [Monitor e informes](monitoring.md). Monitores legacy v1: [Proxy de informes](report-proxy.md). --- @@ -198,9 +198,38 @@ Se arranca siempre que exista un bloque **`PROXY`** (ver `adn-server.example.yam --- +## `DATABASE` (MariaDB) + +**Obligatorio** en configs típicas de servidor de conferencia: cualquier despliegue con **`PROXY`**, o al menos un system **`MASTER`** / **`OPENBRIDGE`**. **No** es obligatorio en flotas **solo echo** (`adn-server.py --echo`). + +| Clave | Significado | +|-------|-------------| +| **DB_SERVER** | Host MariaDB/MySQL. | +| **DB_USERNAME** / **DB_PASSWORD** | Credenciales. | +| **DB_NAME** | Nombre de la base (a menudo la misma que **adn-monitor**, p. ej. `hbmon`). | +| **DB_PORT** | Puerto TCP (por defecto **3306**). | + +**Un solo pool** compartido para: + +- **Persistencia de TG dinámicos** — tabla **`peer_dynamic_tgs`** (TG activados por usuario por hotspot entre reconexiones). El servidor **crea la tabla al arranque** si falta (migración **`004_peer_dynamic_tgs`**, mismo esquema que adn-monitor). +- **Self-service integrado** — tabla **`Clients`** con **`SELF_SERVICE.USE_SELFSERVICE: true`**. + +El arranque aborta con log claro si MariaDB no responde o **`DATABASE`** está incompleto. Instala **`mysqlclient`** (`pip install -e ".[selfservice]"` lo incluye). + +**Recarga en caliente:** cambiar **`DATABASE`** exige **reinicio completo** del proceso. + +Detalle: [Bridges y talkgroups — persistencia TG dinámicos](bridges-and-talkgroups.md#persistencia-tg-dinamicos-mariadb). + +--- + ## `SELF_SERVICE` (MySQL / opciones del panel) -Opcional; requiere `pip install -e ".[selfservice]"` con **`USE_SELFSERVICE: true`**. Usa la misma tabla **`Clients`** y parámetros PBKDF2 que **adn-monitor**. Las claves coinciden con la documentación del monitor — ver [Self-service](../../monitor/self-service.md) y [Proxy hotspot](hotspot-proxy.md#claves-self_service). +Opcional; requiere `pip install -e ".[selfservice]"` con **`USE_SELFSERVICE: true`**. Usa el bloque **`DATABASE`** anterior (sin claves DB separadas en **`SELF_SERVICE`**). Los parámetros PBKDF2 deben **coincidir** con **adn-monitor**. Ver [Self-service](../../monitor/self-service.md) y [Proxy hotspot](hotspot-proxy.md#claves-self_service). + +| Clave | Significado | +|-------|-------------| +| **USE_SELFSERVICE** | Activa sincronización de opciones desde el panel (`true` / `false`). | +| **PBKDF2_SALT** / **PBKDF2_ITERATIONS** | Deben coincidir con **`adn-monitor.yaml`** / herramienta de contraseñas. | --- diff --git a/docs/es/server/user-guide/hotspot-proxy.md b/docs/es/server/user-guide/hotspot-proxy.md index 6614ca0..1308b66 100644 --- a/docs/es/server/user-guide/hotspot-proxy.md +++ b/docs/es/server/user-guide/hotspot-proxy.md @@ -72,9 +72,10 @@ Misma semántica que **`adn-monitor.yaml`** — tabla **`Clients`** compartida, | Clave | Rol | |-------|-----| | **USE_SELFSERVICE** | Activa sincronización de opciones con MySQL (`true` / `false`). | -| **DB_SERVER**, **DB_USERNAME**, **DB_PASSWORD**, **DB_NAME**, **DB_PORT** | Conexión MySQL. | | **PBKDF2_SALT**, **PBKDF2_ITERATIONS** | Deben **coincidir** con **`adn-monitor.yaml`** para el hash de contraseñas. | +La conexión MariaDB está en el bloque **`DATABASE`** (compartido con persistencia de TG dinámicos) — ver [Configuración](configuration.md#database-mariadb). + Al arrancar el servidor registra **`(SELF_SERVICE) Database connection test: OK`** y **`(SELF_SERVICE) Enabled`** si el pool conecta. El self-service es **asíncrono**; el reenvío de voz no se bloquea por latencia de BD. Detalle del flujo en el panel: [Self-service](../../monitor/self-service.md). diff --git a/docs/es/server/user-guide/introduction.md b/docs/es/server/user-guide/introduction.md index 645a660..9ccd999 100644 --- a/docs/es/server/user-guide/introduction.md +++ b/docs/es/server/user-guide/introduction.md @@ -17,8 +17,8 @@ Enrutado, temporizadores, control de bucle OpenBridge y manejo de protocolo est | Subsistema | Rol | |------------|-----| -| **Bridge router** | Tabla `BRIDGES`: qué sistemas reenvían qué TG en qué slot; bridges dinámicos; bridges estáticos/stat. | -| **Protocolo HBP** | Autenticación, ingreso/salida DMRD, repetición a peers, filtros TG. | +| **Bridge router** | Tabla `BRIDGES`: qué sistemas reenvían qué TG en qué slot; bridges dinámicos; bridges estáticos/stat; **restauración MariaDB de TG dinámicos** al reconectar. | +| **Protocolo HBP** | Autenticación, ingreso/salida DMRD, repetición a peers, filtros TG, seguimiento de **sesión UA por peer**. | | **OpenBridge** | Ingreso DMRE, límite de saltos, control de bucle (`min(1ST)`), BCSQ/BCKA si están habilitados. | | **Voz** | Ficheros AMBE, anuncios programados, tubería TTS, reproducción bajo demanda (TG 9991–9999). | | **Informes** | Canal TCP netstring hacia **adn-monitor** (y paneles compatibles): config, estado de bridges, eventos de llamada (informe v2 JSON). | @@ -28,10 +28,11 @@ Enrutado, temporizadores, control de bucle OpenBridge y manejo de protocolo est - **Echo / playback** — `adn-server.py --echo` con `adn-echo.yaml` mínimo; ver [Echo](echo.md). - **Proxy hotspot integrado** — `PROXY` en **`adn-server.yaml`**; ver [Proxy hotspot](hotspot-proxy.md). +- **Proxy de informes (paneles legacy)** — **[ADN-report-proxy](https://github.com/ce5rpy/ADN-report-proxy)** opcional para que **adn-server 2.x** alimente monitores antiguos estilo HBMonitor / FDMR (wire v1); ver [Proxy de informes](report-proxy.md). No se usa con **adn-monitor 2.x**. ## Siguientes pasos -- [Configuración](configuration.md) — ficheros, `GLOBAL`, **MASTER** / **PEER** / **OPENBRIDGE**, ACL, informes, **`PROXY`**, **`SELF_SERVICE`**, alias, fusión de voz. +- [Configuración](configuration.md) — ficheros, `GLOBAL`, **MASTER** / **PEER** / **OPENBRIDGE**, ACL, **`DATABASE`**, informes, **`PROXY`**, **`SELF_SERVICE`**, alias, fusión de voz. - [Bridges y talkgroups](bridges-and-talkgroups.md) — cómo funciona `BRIDGES`. - [Números especiales](special-numbers.md) — TG 4000, servicios de información, eco. - [Proxy hotspot](hotspot-proxy.md) — **`PROXY`** / **`SELF_SERVICE`** integrados en `adn-server.yaml`. diff --git a/docs/es/server/user-guide/monitoring.md b/docs/es/server/user-guide/monitoring.md index 0eca217..7b43f9f 100644 --- a/docs/es/server/user-guide/monitoring.md +++ b/docs/es/server/user-guide/monitoring.md @@ -12,6 +12,12 @@ Cuando **`REPORTS`** está habilitado en la config del servidor, el **ADN DMR Pe **Acoplamiento de versiones:** **servidor 1.0.x + monitor 1.0.x** = report v1 (tags). **servidor 2.x** emite **solo report v2** — requiere **monitor 2.x**. Sin wire `dual`; monitor 1.0.x no decodifica este servidor. +### Paneles legacy (report-proxy) + +Si mantienes un **panel antiguo** cuyo backend monitor solo habla **informe v1** (pickle/CSV, sin HELLO v2), **no puede** conectarse a **adn-server 2.x** en `REPORTS.REPORT_PORT`. Usa el opcional **[ADN-report-proxy](https://github.com/ce5rpy/ADN-report-proxy)** para traducir **v2 → v1**: el proxy se conecta al servidor; el monitor legacy se conecta al proxy. **adn-monitor 2.x** **no** necesita este proxy — conéctalo directamente al servidor. + +Ver [Proxy de informes (paneles legacy)](report-proxy.md) para topología, `REPORT_CLIENTS`, puertos y orden de arranque. + Las pilas antiguas (**legado** estilo `adn-dmr-server`) pueden **omitir** HELLO. **adn-monitor** espera hasta **`ADN_CONNECTION.HELLO_TIMEOUT_MS`** (ver [Configuración del monitor](../../monitor/configuration.md#adn_connection)); si no llega HELLO, asume informes **legacy**. El **monitor** decodifica estos mensajes, actualiza **CTABLE** / **BTABLE** y (con MySQL configurado) persiste Last Heard / estadísticas. @@ -40,6 +46,19 @@ En **WARNING**: JSON HELLO inválido (`(REPORT) HELLO payload not valid JSON`), El panel muestra el estado **operativo** desde **START** (canónico); el **log del Monitor** muestra **INGRESS** más **START** para depurar duplicados en malla. +### Chips UA dinámicos (OPTIONS del hotspot) + +El monitor rastrea TG **activados por usuario** por hotspot para los chips índigo del panel: + +| OPTIONS del peer | Fuente en el monitor | +|----------------|----------------------| +| **SINGLE=1** | **`UA_SESSIONS`** en **CONFIG_SND** / `dashboard_state` (el servidor es fuente de verdad). | +| **SINGLE=0** | Eventos de voz (`BRDG_EVENT` / `voice_event`) — varios dinámicos por slot hasta limpiar. | + +**TG 4000** limpia el estado UA con **`GROUP VOICE,INGRESS,RX`** y destino **4000** (el servidor lo envía porque la ruta de voz corta antes y no emite un **START** normal). El monitor **no** debe registrar **4000** como TG dinámico. + +**Emparejamiento de versiones:** **adn-server 2.0.0-rc.3** + **adn-monitor 2.0.0-rc.4** para persistencia de TG dinámicos y sincronización TG 4000 en el monitor. + ## Rotación de logs (logrotate) Tras que **logrotate** renombre o mueva el fichero de log (patrón habitual: **`create`** — el fichero antiguo rota y aparece uno **nuevo vacío** en la ruta configurada), el proceso puede seguir con el descriptor abierto sobre el **inodo anterior**. Los logs parecen “no escribirse” en la ruta actual hasta que el proceso **reabra** los `FileHandler`. diff --git a/docs/es/server/user-guide/report-proxy.md b/docs/es/server/user-guide/report-proxy.md new file mode 100644 index 0000000..76bdc81 --- /dev/null +++ b/docs/es/server/user-guide/report-proxy.md @@ -0,0 +1,100 @@ +# Proxy de informes (paneles legacy) + +**ADN DMR Peer Server 2.x** emite **informe wire v2** (JSON por TCP). **adn-monitor 2.x** entiende ese protocolo y se conecta **directamente** al servidor — no hace falta ningún componente extra. + +Algunos **stacks de panel legacy** siguen trayendo su propio backend `dashboard.py` / `monitor.py` y solo hablan **informe wire v1** (pickle `CONFIG_SND` / `BRIDGE_SND`, CSV `BRDG_EVENT`). Esos monitores **no pueden** conectarse a **adn-server 2.x** en el puerto de informes. + +El paquete opcional **[ADN-report-proxy](https://github.com/ce5rpy/ADN-report-proxy)** queda en medio: se conecta **upstream** al servidor real (v2), escucha **downstream** donde el monitor legacy espera el servidor (v1) y traduce **v2 → v1**. + +| Stack | Servidor upstream | ¿Funciona sin proxy? | +|-------|-------------------|----------------------| +| **adn-monitor 2.x** (React) | **adn-server 2.x** | Sí — conectar a `REPORTS.REPORT_PORT` | +| Panel legacy + monitor incluido (v1) | **adn-dmr-server** (v1) | Sí — directo al puerto de informes del servidor | +| Panel legacy + monitor incluido (v1) | **adn-server 2.x** (v2) | **No** — usar **report-proxy** | + +Objetivos legacy típicos: forks antiguos de **ADN-Dashboard**, despliegues **HBMonitor** / **FDMR Monitor** que aún ejecutan un proceso monitor Python contra `dashboard.cfg` / `monitor.cfg`. + +## Topología + +```text +┌───────────────────┐ +│ adn-server │ +│ ESCUCHA :4321 │ +└─────────▲─────────┘ + │ + │ TCP v2 JSON + │ (report-proxy es CLIENTE) + │ +┌─────────┴─────────┐ +│ report-proxy │ +│ ESCUCHA :4322 │ +└─────────▲─────────┘ + │ + │ TCP v1 pickle + │ (panel legacy es CLIENTE) + │ +┌─────────┴─────────┐ +│ panel legacy │ +│ monitor.py │ +└───────────────────┘ +``` + +| Componente | Rol | Puerto por defecto | Config | Clave | +|------------|-----|-------------------|--------|-------| +| **adn-server** | Escucha clientes de informes | **4321** | `adn-server.yaml` | `REPORTS.REPORT_PORT` | +| **report-proxy** | Se conecta al servidor | 4321 | `report-proxy.yaml` | `UPSTREAM.PORT` | +| **report-proxy** | Escucha al monitor legacy | **4322** | `report-proxy.yaml` | `LISTEN.PORT` | +| **Panel legacy** | Se conecta al proxy | **4322** | `dashboard.cfg` | `SERVER_PORT` | + +**No** apuntes el panel legacy al **4321** — es el puerto v2 del servidor. + +**No** pongas `UPSTREAM.PORT` en **4322** — es el puerto de escucha del propio proxy. + +## Lado servidor (`adn-server.yaml`) + +Los informes deben estar activos y la **IP del host del proxy** debe estar en la lista permitida: + +```yaml +REPORTS: + REPORT: true + REPORT_INTERVAL: 60 + REPORT_PORT: 4321 + REPORT_CLIENTS: "127.0.0.1" # IP de la máquina donde corre report-proxy +``` + +Si el proxy corre en otro host, usa la **IP de ese host** en `REPORT_CLIENTS`, no solo `127.0.0.1`. Ver [Configuración](configuration.md#reports) para todas las claves de `REPORTS`. + +## Proxy y panel legacy + +Instala y ejecuta el proxy desde el repositorio **[ADN-report-proxy](https://github.com/ce5rpy/ADN-report-proxy)** (`report-proxy.yaml`, `python3 report-proxy.py -c report-proxy.yaml`). Apunta `UPSTREAM` al `REPORT_PORT` del servidor y `LISTEN` al puerto que usa el monitor legacy (a menudo **4322**). + +En `dashboard.cfg` / `monitor.cfg` legacy: + +```ini +[SERVER CONNECTION] +SERVER_IP = 127.0.0.1 +SERVER_PORT = 4322 +``` + +`SERVER_IP` es el host donde **report-proxy** escucha, no necesariamente el host de adn-server. + +**Orden de arranque:** adn-server → report-proxy → backend monitor legacy. + +Pasos completos, ejemplos multi-host, comprobaciones y errores frecuentes: **[README de ADN-report-proxy](https://github.com/ce5rpy/ADN-report-proxy#configuration-legacy-dashboard--adn-server-2x)**. + +## Traducción de wire (resumen) + +| Upstream (v2 desde adn-server) | Downstream (v1 al monitor legacy) | +|--------------------------------|-----------------------------------| +| `HELLO` (`report_protocol: 2`) | `HELLO` (`protocol: 1`) | +| `STATE_SND` / `dashboard_state` | `CONFIG_SND` (pickle) | +| `ROUTING_TABLE_SND` | `BRIDGE_SND` (pickle) | +| `TOPOLOGY_SND` | `CONFIG_SND` (pickle) | +| `VOICE_EVENT_SND` | `BRDG_EVENT` (CSV) | + +Detalle del esquema v2: [Protocolo de informes v2 (JSON)](../protocols/report-v2.md). + +## Ver también + +- [Monitor e informes](monitoring.md) — canal de informes, emparejamiento con **adn-monitor**, líneas de log. +- [Descripción general de ADN Monitor](../../monitor/index.md) — panel recomendado para **adn-server 2.x** (sin proxy). diff --git a/docs/es/server/user-guide/special-numbers.md b/docs/es/server/user-guide/special-numbers.md index b74bec8..e00e35b 100644 --- a/docs/es/server/user-guide/special-numbers.md +++ b/docs/es/server/user-guide/special-numbers.md @@ -56,17 +56,22 @@ La activación/desactivación in-band de bridges se aplica sobre **voice termina - En bridges reflector (`#...`), el manejo in-band solo se evalúa cuando el destino es **TG 9**. - Por eso los mensajes de reflector y el cableado de marcado usan TG 9, mientras que llamadas privadas no disparan esa lógica de temporizadores de bridge. -## TG / ID 4000 — desactivar bridges dinámicos +## TG / ID 4000 — desactivar bridges dinámicos {#tg--id-4000--desactivar-bridges-dinamicos} -**Propósito:** borrar **bridges dinámicos activados por usuario** para el sistema que recibe la llamada. +**Propósito:** Borrar el estado **activado por usuario (dinámico)** del hotspot que pulsa **4000**. **TG 4000 no es** un talkgroup que deba monitorizarse ni persistirse — es un **comando de reset**. -**Comportamiento:** +**Comportamiento (cabecera de voz de grupo):** + +- Limpia sesiones UA del peer en memoria (**todos los slots** de ese peer). +- Borra filas correspondientes en **`peer_dynamic_tgs`** (MariaDB). +- Limpia campos RX obsoletos en **STATUS** para que un **RPTO** posterior no re-sembré el TG antiguo. +- Ejecuta **desactivación in-band** de bridges en el slot (como legacy). +- Envía **`GROUP VOICE,INGRESS,RX,…,4000`** al monitor (no **START**) para que los chips **SINGLE=0** se limpien **sin** encender TX en vivo. +- En MASTER **inject-only**, empuja **CONFIG_SND** actualizado al monitor. -- Implementado para tráfico de **grupo** con destino **4000** (y comprobaciones relacionadas en el router). -- Se ejecuta **antes** que la ACL normal de TG en la ruta OpenBridge para que el comando no quede bloqueado por listas permitidas. -- Invoca **`deactivate_all_dynamic_bridges`**: desactiva filas dinámicas que no sean stat ni reflector. +**Inject-only frente a global:** Con **`PROXY`** integrado, el reset es **por peer** (solo los dinámicos de ese hotspot). Sin filtro inject-only, sigue aplicándose legacy **`deactivate_all_dynamic_bridges`** a todo el system. -Úsalo cuando los operadores necesiten **reiniciar** el enrutado dinámico sin reiniciar el servidor. +**TG 4000 no debe aparecer** como chip UA dinámico en el monitor ni en `peer_dynamic_tgs`. ### Impacto de `SINGLE_MODE` en la lógica de desactivación diff --git a/mkdocs.es.yml b/mkdocs.es.yml index 81c53d4..abfadca 100644 --- a/mkdocs.es.yml +++ b/mkdocs.es.yml @@ -56,6 +56,7 @@ nav: - Llamadas privadas: server/user-guide/private-calls.md - Voz, anuncios y TTS: server/user-guide/voice-and-tts.md - Monitor e informes: server/user-guide/monitoring.md + - Proxy de informes (paneles legacy): server/user-guide/report-proxy.md - Proxy hotspot (integrado): server/user-guide/hotspot-proxy.md - Echo (reproducción): server/user-guide/echo.md - Créditos y licencia: server/user-guide/attribution.md diff --git a/mkdocs.yml b/mkdocs.yml index eecd9fc..9d8c002 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -56,6 +56,7 @@ nav: - Private calls: server/user-guide/private-calls.md - Voice, announcements, and TTS: server/user-guide/voice-and-tts.md - Monitoring and reports: server/user-guide/monitoring.md + - Report proxy (legacy dashboards): server/user-guide/report-proxy.md - Hotspot proxy (integrated): server/user-guide/hotspot-proxy.md - Echo (playback): server/user-guide/echo.md - Credits & license: server/user-guide/attribution.md