Skip to content

Commit ea09328

Browse files
committed
feat(routing): Phase 1.3 — RPC observability, relay session reuse, tombstone hardening
Routing table fixes: - Tombstone entries now set ExpiresAt on withdrawal (RemoveDirectPeer, InvalidateTransitRoutes) so TickTTL cleans them after TTL instead of immediately or never - Same-SeqNo updates can no longer resurrect withdrawn routes — only strictly newer SeqNo from the origin supersedes a tombstone - IsExpired boundary fix: exact-boundary timestamps now correctly treated as expired (!now.Before instead of now.After) Relay key sync: - New syncSenderKeys() reuses existing outbound session for on-demand key fetch instead of opening a fresh TCP connection - handleRelayMessage accepts optional syncSession parameter to avoid deadlock on single-reader inboxCh when called from within session loop - syncPeer auth phase skips up to 5 interleaved non-auth frames (announce_routes race during handshake) RPC routing observability: - New routing_commands.go: fetch_route_table, fetch_route_summary, fetch_route_lookup with RoutingProvider interface - New routing_provider.go: bridges node.Service to RPC layer - PeerTransport filters out disconnected peers via health check - Console parser rejects extra arguments for no-arg routing commands - snapshot_at field added to fetch_route_summary response - Full handler test coverage (handler_routing_test.go) Documentation: - Roadmap rewritten to reflect current state (three delivery mechanisms) - Diagram updated: Node D shows routing-table-based path selection - New docs/rpc/routing.md with full field specs (EN + RU) - routing.md updated with snapshot_at and tombstone semantics
1 parent 51a5c3e commit ea09328

37 files changed

Lines changed: 3055 additions & 1356 deletions

docs/roadmap.md

Lines changed: 73 additions & 343 deletions
Large diffs are not rendered by default.

docs/roadmap.ru.md

Lines changed: 105 additions & 370 deletions
Large diffs are not rendered by default.

docs/routing.md

Lines changed: 54 additions & 20 deletions
Large diffs are not rendered by default.

docs/rpc.md

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ graph TD
175175
REG_NTC["RegisterNoticeCommands<br/>fetch_notices"]
176176
REG_MSH["RegisterMeshCommands<br/>fetch_relay_status"]
177177
REG_MET["RegisterMetricsCommands<br/>fetch_traffic_history"]
178+
REG_RTE["RegisterRoutingCommands<br/>fetch_route_table · fetch_route_summary · fetch_route_lookup*"]
178179
179180
REG_SYS -->|"Register()"| TABLE
180181
REG_NET -->|"Register()"| TABLE
@@ -184,16 +185,18 @@ graph TD
184185
REG_NTC -->|"Register()"| TABLE
185186
REG_MSH -->|"Register()"| TABLE
186187
REG_MET -->|"Register()"| TABLE
188+
REG_RTE -->|"Register()"| TABLE
187189
188190
TABLE --> SERVER["Fiber HTTP Server<br/>(wraps CommandTable)"]
189191
TABLE --> WINDOW["Desktop Window<br/>(direct access)"]
190192
191193
style REG_CHT fill:#555,stroke:#888
192194
style REG_MSG fill:#555,stroke:#888
195+
style REG_RTE fill:#555,stroke:#888
193196
```
194197
*Diagram 4 — Command registration.*
195198

196-
Commands marked with `*` are mode-gated: when their provider is nil (standalone node), they are registered as unavailable via `RegisterUnavailable()` — returning 503 and hidden from help. `send_dm` requires DMRouterProvider; chatlog commands require ChatlogProvider; `fetch_traffic_history` requires MetricsProvider.
199+
Commands marked with `*` are mode-gated: when their provider is nil (standalone node), they are registered as unavailable via `RegisterUnavailable()` — returning 503 and hidden from help. `send_dm` requires DMRouterProvider; chatlog commands require ChatlogProvider; `fetch_traffic_history` requires MetricsProvider; routing commands require RoutingProvider.
197200

198201
### Configuration
199202

@@ -222,7 +225,7 @@ The architecture separates command execution from transport:
222225
// CommandTable — single source of truth for all commands.
223226
// RegisterAllCommands is the single registration point — both bootstrap and tests use it.
224227
table := rpc.NewCommandTable()
225-
rpc.RegisterAllCommands(table, nodeService, chatlogProvider, dmRouter, metricsCollector)
228+
rpc.RegisterAllCommands(table, nodeService, chatlogProvider, dmRouter, metricsCollector, routingProvider)
226229

227230
// Desktop: replace base ping/get_peers with diagnostic-enriched versions,
228231
// and hello with desktop identity (Client: "desktop").
@@ -250,6 +253,7 @@ server, _ := rpc.NewServer(cfg, table, nodeService)
250253
| **notice** | fetch_notices | Always registered |
251254
| **mesh** | fetch_relay_status | Always registered |
252255
| **metrics** | fetch_traffic_history | Always registered; unavailable (503, hidden from help) when MetricsProvider is nil |
256+
| **routing** | fetch_route_table, fetch_route_summary, fetch_route_lookup | Always registered; unavailable (503, hidden from help) when RoutingProvider is nil |
253257

254258
#### Dependency Injection
255259

@@ -302,6 +306,7 @@ Per-command documentation is in the [rpc/](rpc/) folder. See [rpc/README.md](rpc
302306
| [Notice](rpc/notice.md) | `fetch_notices` | [rpc/notice.md](rpc/notice.md) |
303307
| [Mesh](rpc/mesh.md) | `fetch_relay_status` | [rpc/mesh.md](rpc/mesh.md) |
304308
| [Metrics](rpc/metrics.md) | `fetch_traffic_history` | [rpc/metrics.md](rpc/metrics.md) |
309+
| [Routing](rpc/routing.md) | `fetch_route_table`, `fetch_route_summary`, `fetch_route_lookup` | [rpc/routing.md](rpc/routing.md) |
305310

306311
### corsa-cli
307312

@@ -597,6 +602,7 @@ graph TD
597602
REG_NTC["RegisterNoticeCommands<br/>fetch_notices"]
598603
REG_MSH["RegisterMeshCommands<br/>fetch_relay_status"]
599604
REG_MET["RegisterMetricsCommands<br/>fetch_traffic_history"]
605+
REG_RTE["RegisterRoutingCommands<br/>fetch_route_table · fetch_route_summary · fetch_route_lookup*"]
600606
601607
REG_SYS -->|"Register()"| TABLE
602608
REG_NET -->|"Register()"| TABLE
@@ -606,16 +612,18 @@ graph TD
606612
REG_NTC -->|"Register()"| TABLE
607613
REG_MSH -->|"Register()"| TABLE
608614
REG_MET -->|"Register()"| TABLE
615+
REG_RTE -->|"Register()"| TABLE
609616
610617
TABLE --> SERVER["Fiber HTTP сервер<br/>(обёртка над CommandTable)"]
611618
TABLE --> WINDOW["Desktop Window<br/>(прямой доступ)"]
612619
613620
style REG_CHT fill:#555,stroke:#888
614621
style REG_MSG fill:#555,stroke:#888
622+
style REG_RTE fill:#555,stroke:#888
615623
```
616624
*Диаграмма 4 — Регистрация команд.*
617625

618-
Команды с `*` являются mode-gated: при nil-провайдере (standalone нода) они регистрируются как недоступные через `RegisterUnavailable()` — возвращают 503 и скрыты из help. `send_dm` требует DMRouterProvider; chatlog-команды требуют ChatlogProvider; `fetch_traffic_history` требует MetricsProvider.
626+
Команды с `*` являются mode-gated: при nil-провайдере (standalone нода) они регистрируются как недоступные через `RegisterUnavailable()` — возвращают 503 и скрыты из help. `send_dm` требует DMRouterProvider; chatlog-команды требуют ChatlogProvider; `fetch_traffic_history` требует MetricsProvider; routing-команды требуют RoutingProvider.
619627

620628
### Конфигурация
621629

@@ -644,7 +652,7 @@ graph TD
644652
// CommandTable — единственный источник истины для всех команд.
645653
// RegisterAllCommands — единая точка регистрации, используемая и bootstrap, и тестами.
646654
table := rpc.NewCommandTable()
647-
rpc.RegisterAllCommands(table, nodeService, chatlogProvider, dmRouter, metricsCollector)
655+
rpc.RegisterAllCommands(table, nodeService, chatlogProvider, dmRouter, metricsCollector, routingProvider)
648656

649657
// Desktop: замена базовых ping/get_peers на диагностически обогащённые версии,
650658
// а также hello на desktop-идентификацию (Client: "desktop").
@@ -672,6 +680,7 @@ server, _ := rpc.NewServer(cfg, table, nodeService)
672680
| **notice** | fetch_notices | Всегда зарегистрированы |
673681
| **mesh** | fetch_relay_status | Всегда зарегистрированы |
674682
| **metrics** | fetch_traffic_history | Всегда зарегистрирована; недоступна (503, скрыта из help) при MetricsProvider = nil |
683+
| **routing** | fetch_route_table, fetch_route_summary, fetch_route_lookup | Всегда зарегистрированы; недоступны (503, скрыты из help) при RoutingProvider = nil |
675684

676685
#### Внедрение зависимостей
677686

@@ -724,6 +733,7 @@ Mode-gated команды регистрируются через `RegisterUnava
724733
| [Уведомления](rpc/notice.md) | `fetch_notices` | [rpc/notice.md](rpc/notice.md) |
725734
| [Mesh](rpc/mesh.md) | `fetch_relay_status` | [rpc/mesh.md](rpc/mesh.md) |
726735
| [Метрики](rpc/metrics.md) | `fetch_traffic_history` | [rpc/metrics.md](rpc/metrics.md) |
736+
| [Маршрутизация](rpc/routing.md) | `fetch_route_table`, `fetch_route_summary`, `fetch_route_lookup` | [rpc/routing.md](rpc/routing.md) |
727737

728738
### corsa-cli
729739

docs/rpc/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Per-command-group documentation for the CORSA RPC layer. For architecture overvi
1616
| [Notice](notice.md) | `fetch_notices` | [notice.md](notice.md) |
1717
| [Mesh](mesh.md) | `fetch_relay_status` | [mesh.md](mesh.md) |
1818
| [Metrics](metrics.md) | `fetch_traffic_history` | [metrics.md](metrics.md) |
19+
| [Routing](routing.md) | `fetch_route_table`, `fetch_route_summary`, `fetch_route_lookup` | [routing.md](routing.md) |
1920

2021
### Universal Dispatch
2122

@@ -65,6 +66,7 @@ This endpoint is only available when the server is created with a `NodeProvider`
6566
| [Уведомления](notice.md) | `fetch_notices` | [notice.md](notice.md) |
6667
| [Mesh](mesh.md) | `fetch_relay_status` | [mesh.md](mesh.md) |
6768
| [Метрики](metrics.md) | `fetch_traffic_history` | [metrics.md](metrics.md) |
69+
| [Маршрутизация](routing.md) | `fetch_route_table`, `fetch_route_summary`, `fetch_route_lookup` | [routing.md](routing.md) |
6870

6971
### Универсальная диспетчеризация
7072

0 commit comments

Comments
 (0)