@tikoci/centrs 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +107 -2
- package/GLOSSARY.txt +87 -0
- package/README.md +25 -9
- package/SECURITY.md +3 -3
- package/commands/AGENTS.md +3 -2
- package/commands/api/AGENTS.md +212 -0
- package/commands/api/README.md +177 -0
- package/commands/api/examples.md +428 -0
- package/commands/btest/README.md +56 -31
- package/commands/btest/examples.md +35 -10
- package/commands/check/README.md +371 -53
- package/commands/check/examples.md +390 -0
- package/commands/devices/README.md +177 -37
- package/commands/devices/examples.md +148 -0
- package/commands/execute/README.md +48 -7
- package/commands/execute/examples.md +90 -6
- package/commands/retrieve/README.md +37 -51
- package/commands/retrieve/examples.md +40 -9
- package/commands/settings/README.md +286 -22
- package/commands/settings/examples.md +408 -0
- package/commands/terminal/README.md +6 -0
- package/commands/transfer/README.md +32 -2
- package/commands/transfer/examples.md +66 -0
- package/docs/CONSTITUTION.md +40 -15
- package/docs/MATRIX.md +69 -142
- package/docs/errors/README.md +2 -1
- package/docs/errors/cdb/empty-selection.md +19 -0
- package/docs/errors/input/incomplete-gps.md +9 -0
- package/docs/errors/input/invalid-altitude.md +9 -0
- package/docs/errors/input/invalid-bbox.md +9 -0
- package/docs/errors/input/invalid-coordinate.md +9 -0
- package/docs/errors/input/invalid-radius.md +9 -0
- package/docs/errors/internal/settings-failed.md +9 -0
- package/docs/errors/routeros/btest-connection-count-single-stream.md +22 -0
- package/docs/errors/routeros/btest-udp-tx-size-ignored.md +15 -0
- package/docs/errors/settings/consequential-value.md +26 -0
- package/docs/errors/settings/invalid-boolean.md +21 -3
- package/docs/errors/settings/invalid-format.md +18 -3
- package/docs/errors/settings/invalid-integer.md +18 -3
- package/docs/errors/settings/invalid-timeout.md +20 -3
- package/docs/errors/settings/invalid-via.md +22 -3
- package/docs/errors/settings/reserved-key.md +29 -0
- package/docs/errors/settings/skip-env-file-active.md +25 -0
- package/docs/errors/settings/unknown-key.md +25 -0
- package/docs/errors/usage/fanout-not-supported.md +16 -0
- package/docs/errors/usage/invalid-method.md +23 -0
- package/package.json +9 -9
- package/src/api-fanout.ts +454 -0
- package/src/api.ts +1627 -0
- package/src/btest.ts +61 -1
- package/src/cli/api.ts +660 -0
- package/src/cli/btest.ts +20 -2
- package/src/cli/common.ts +75 -0
- package/src/cli/devices.ts +235 -6
- package/src/cli/discover.ts +3 -1
- package/src/cli/execute.ts +107 -6
- package/src/cli/mcp.ts +8 -1
- package/src/cli/retrieve.ts +135 -90
- package/src/cli/selection.ts +200 -0
- package/src/cli/settings.ts +286 -0
- package/src/cli/terminal.ts +22 -7
- package/src/cli/transfer.ts +171 -47
- package/src/cli.ts +29 -0
- package/src/core/error-catalog.ts +69 -0
- package/src/core/fanout.ts +301 -0
- package/src/core/inspect.ts +170 -0
- package/src/devices.ts +212 -20
- package/src/discover.ts +7 -2
- package/src/execute-fanout.ts +438 -0
- package/src/execute.ts +134 -70
- package/src/index.ts +166 -9
- package/src/mcp/config.ts +12 -2
- package/src/mcp/tools.ts +137 -2
- package/src/protocols/adapter.ts +357 -9
- package/src/protocols/btest-session.ts +279 -46
- package/src/protocols/btest.ts +6 -2
- package/src/protocols/index.ts +11 -5
- package/src/protocols/native-api.ts +223 -30
- package/src/resolver/cdb.ts +10 -2
- package/src/resolver/comment-kv.ts +58 -4
- package/src/resolver/config-file.ts +136 -0
- package/src/resolver/facts.ts +78 -0
- package/src/resolver/geo.ts +453 -0
- package/src/resolver/index.ts +46 -0
- package/src/resolver/mac.ts +12 -3
- package/src/resolver/selection.ts +304 -0
- package/src/resolver/settings.ts +54 -5
- package/src/resolver/target.ts +20 -2
- package/src/retrieve-fanout.ts +232 -268
- package/src/retrieve.ts +69 -94
- package/src/settings.ts +1078 -0
- package/src/terminal.ts +11 -1
- package/src/transfer-fanout.ts +527 -0
- package/src/transfer.ts +61 -11
- package/commands/stream/README.md +0 -70
package/commands/btest/README.md
CHANGED
|
@@ -17,7 +17,10 @@ on the centrs **server**; `test/integration/btest-client.test.ts` runs the centr
|
|
|
17
17
|
**client** against a real RouterOS `/tool/bandwidth-server` over a host→guest
|
|
18
18
|
`tcp:2000` forward — unauthenticated TCP receive, an **EC-SRP5 client proof
|
|
19
19
|
verified by RouterOS's own verifier**, and a wrong-password reject. TCP
|
|
20
|
-
multi-connection (`connection-count > 1`) data fan-out is
|
|
20
|
+
multi-connection (`connection-count > 1`) data fan-out is implemented for
|
|
21
|
+
unauthenticated tests (the client joins the negotiated extra connections; the join
|
|
22
|
+
format is grounded against RouterOS 7.23.1); authenticated sessions stay
|
|
23
|
+
single-stream. See
|
|
21
24
|
`docs/MATRIX.md` ("Peer measurement (`btest`)") for the cell states — that is the
|
|
22
25
|
only status surface. v1 scope: **both** modes (client + server), **EC-SRP5 +
|
|
23
26
|
unauthenticated** auth, **TCP and UDP** tests. Legacy pre-6.43 double-MD5 is out of
|
|
@@ -85,7 +88,7 @@ centrs btest server [--authenticate[=false]] [--user U] [--password P] \
|
|
|
85
88
|
| `--direction <receive\|transmit\|both>` | `direction`, default `receive` | `receive` = download (server→client), `transmit` = upload. |
|
|
86
89
|
| `--duration <dur>` | `duration` | Bounds the run; reuses `parseDuration`. Omit for open-ended (Ctrl-C). |
|
|
87
90
|
| `--interval <dur>` | `interval`, default `1s` | Report cadence (`20ms`..`5s`). One report frame per interval. |
|
|
88
|
-
| `--connection-count <n>` | `connection-count` (1..255) | **TCP only.** Parallel TCP data connections. |
|
|
91
|
+
| `--connection-count <n>` | `connection-count` (1..255) | **TCP only.** Parallel TCP data connections. centrs opens the negotiated extra connections (join format grounded against RouterOS 7.23.1) so throughput aggregates across streams. **Authenticated (EC-SRP5) sessions stay single-stream** — the post-auth token is not captured — and emit a `routeros/btest-connection-count-single-stream` warning. |
|
|
89
92
|
| `--local-udp-tx-size <n>` | `local-udp-tx-size` (28..64000) | **UDP only.** Client→server packet size. |
|
|
90
93
|
| `--remote-udp-tx-size <n>` | `remote-udp-tx-size` (28..64000) | **UDP only.** Server→client packet size. |
|
|
91
94
|
| `--local-tx-speed <bps>` | `local-tx-speed` | Cap on client→server rate (bits/sec). |
|
|
@@ -120,10 +123,20 @@ test, data then flows on the server's allocated UDP ports
|
|
|
120
123
|
from sequence gaps. For a TCP test, the bulk data rides `connection-count` TCP
|
|
121
124
|
connections and goodput is measured on the data stream (TCP/IP headers excluded,
|
|
122
125
|
matching RouterOS accounting). For multi-connection TCP the server's OK response
|
|
123
|
-
carries a 2-byte **session token**; the
|
|
124
|
-
|
|
126
|
+
carries a 2-byte **session token**; the client opens `connection-count − 1`
|
|
127
|
+
additional connections, each presenting a 16-byte join `[token:u16 BE][0x02][0 …]`
|
|
128
|
+
(grounded against RouterOS 7.23.1, direction-independent) to join the same test
|
|
129
|
+
without re-auth, and drives them into the shared counters so throughput aggregates.
|
|
130
|
+
Throughput and CPU are exchanged
|
|
125
131
|
once per `interval` as a 12-byte **status message** on the TCP channel
|
|
126
|
-
(`[0x07][0x80|cpu][00 00][seq u32 LE][bytesReceived u32 LE]`).
|
|
132
|
+
(`[0x07][0x80|cpu][00 00][seq u32 LE][bytesReceived u32 LE]`). The receiver of a
|
|
133
|
+
transmit (server for `transmit`, both peers for `both`) sends this so the
|
|
134
|
+
transmitter paces from the peer's `bytesReceived`. For `direction=both` the
|
|
135
|
+
status frames are **interleaved into the bulk data stream** (no length framing),
|
|
136
|
+
so the client demuxes them out of its receive loop by their structural marker —
|
|
137
|
+
without that feedback the client's TX saturates the link and starves
|
|
138
|
+
server→client RX. RouterOS clears the CPU high bit the centrs client sets, so the
|
|
139
|
+
marker matches on the two reserved zero bytes, not the high bit.
|
|
127
140
|
|
|
128
141
|
### Authentication (EC-SRP5)
|
|
129
142
|
|
|
@@ -141,7 +154,7 @@ will not offer EC-SRP5 against an `authenticate=yes` server) maps to
|
|
|
141
154
|
|
|
142
155
|
btest runs over time, so it emits **live records** during the run plus a final
|
|
143
156
|
**summary**. v1 keeps the formats simple and **defers a broader JSON-streaming
|
|
144
|
-
decision** — it does *not* adopt
|
|
157
|
+
decision** — it does *not* adopt `api --stream`'s NDJSON-stream-of-envelopes
|
|
145
158
|
contract yet (see Open questions):
|
|
146
159
|
|
|
147
160
|
- **`text`** (default) — human-readable live reports during the run
|
|
@@ -214,10 +227,11 @@ Decided with the user. Both cells have direct gated `CHR-passed` evidence:
|
|
|
214
227
|
maps onto the guest bandwidth server on 2000 (the same SLIRP inbound path that
|
|
215
228
|
already carries REST/SSH — no firewall change). The centrs client dials
|
|
216
229
|
`127.0.0.1:<host port>` and proves **TCP receive**, unauth and **EC-SRP5** (its
|
|
217
|
-
client proof verified by RouterOS's real server verifier),
|
|
218
|
-
reject
|
|
219
|
-
|
|
220
|
-
|
|
230
|
+
client proof verified by RouterOS's real server verifier), a wrong-password
|
|
231
|
+
reject, **TCP multi-connection fan-out** (`connection-count=4`), and **UDP
|
|
232
|
+
receive/both**. The UDP server→client return needs no UDP forward: it rides the
|
|
233
|
+
guest→host SLIRP gateway (`10.0.2.2:clientUdpPort`, the same path the server cell
|
|
234
|
+
uses), which works because the client socket is left unconnected (#86, #88).
|
|
221
235
|
|
|
222
236
|
The fast/deterministic backstop under both is **centrs client ↔ centrs server
|
|
223
237
|
loopback** (`127.0.0.1`, injected sockets) covering the full client↔server matrix,
|
|
@@ -226,32 +240,43 @@ EC-SRP5 both roles, and the option-grammar rejects.
|
|
|
226
240
|
while implementing the EC-SRP5 framing and the server-side verifier; it is **not**
|
|
227
241
|
an integration test (it cannot run in CI) and **not** part of the long-term plan.
|
|
228
242
|
|
|
229
|
-
**Honest grounding caveat:** both cells are now directly CHR-passed
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
243
|
+
**Honest grounding caveat:** both cells are now directly CHR-passed, **including
|
|
244
|
+
TCP multi-connection fan-out** — `test/integration/btest-client.test.ts` gates a
|
|
245
|
+
centrs client opening `connection-count=4` against a real RouterOS
|
|
246
|
+
`/tool/bandwidth-server`; RouterOS accepts all 3 secondary joins and data flows on
|
|
247
|
+
every connection (`activeConnections: 4`). The *throughput increase* multiple
|
|
248
|
+
streams give is a WAN/latency property and is not observable over the near-zero-
|
|
249
|
+
latency SLIRP loopback, so the gate asserts the fan-out, not a higher number (the
|
|
250
|
+
per-connection drive is asserted deterministically by the loopback unit test).
|
|
251
|
+
**UDP client receive/both is now CHR-gated too** — the server→client return rides
|
|
252
|
+
the guest→host SLIRP gateway, no UDP forward needed (#88). The remaining fan-out
|
|
253
|
+
edge is **authenticated** multi-connection (capturing the EC-SRP5 post-auth token),
|
|
254
|
+
still single-stream.
|
|
233
255
|
|
|
234
256
|
## Open questions
|
|
235
257
|
|
|
236
|
-
- **JSON streaming is deliberately deferred.** btest does not adopt
|
|
237
|
-
|
|
238
|
-
returns a single summary envelope for `json` / `yaml`. Revisit a
|
|
239
|
-
shape — ideally shared with `stream` — once
|
|
240
|
-
- **UDP receive/both
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
- **
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
258
|
+
- **JSON streaming is deliberately deferred.** btest does not adopt
|
|
259
|
+
`api --stream`'s NDJSON-stream-of-envelopes contract yet; v1 streams `text` /
|
|
260
|
+
`csv` and returns a single summary envelope for `json` / `yaml`. Revisit a
|
|
261
|
+
streaming-JSON shape — ideally shared with `api --stream` — once it has settled.
|
|
262
|
+
- **UDP client receive/both is gated (#88).** The client cell
|
|
263
|
+
(`test/integration/btest-client.test.ts`) lands real UDP server→client throughput:
|
|
264
|
+
the return rides the guest→host SLIRP gateway (`10.0.2.2:clientUdpPort`), needing
|
|
265
|
+
no UDP forward and no quickchr change — it works because the client socket is left
|
|
266
|
+
unconnected (#86).
|
|
267
|
+
- **Only the server-cell host→guest UDP direction stays unproven.** The server cell
|
|
268
|
+
gates UDP *transmit* (guest→host, which SLIRP NATs cleanly); the reverse (centrs
|
|
269
|
+
server → CHR client, host→guest) would need a UDP hostfwd for the data ports, so it
|
|
270
|
+
is not yet asserted. `btest.exe` (wine) is the coding-time grounding peer, not CI.
|
|
271
|
+
- **Authenticated multi-connection stays single-stream.** Fan-out negotiates the
|
|
272
|
+
session token from the unauthenticated OK; capturing the EC-SRP5 post-auth token
|
|
273
|
+
to fan out authenticated tests is a follow-up (#103). centrs warns
|
|
274
|
+
(`routeros/btest-connection-count-single-stream`) when the realized connection
|
|
275
|
+
count falls short of the request. The **server-side** secondary-accept is its own
|
|
276
|
+
follow-up (#100).
|
|
251
277
|
|
|
252
278
|
## Out of scope (v1)
|
|
253
279
|
|
|
254
|
-
Legacy pre-6.43 double-MD5 auth;
|
|
255
|
-
UDP needs SLIRP reverse-NAT); the ≥3-router "test-through" topology RouterOS
|
|
280
|
+
Legacy pre-6.43 double-MD5 auth; the ≥3-router "test-through" topology RouterOS
|
|
256
281
|
recommends for measuring a *transit* device (centrs is an endpoint peer); TUI/proxy
|
|
257
282
|
btest frontends (later, over the stable core).
|
|
@@ -15,17 +15,19 @@ matrix's honest grounding split (`docs/MATRIX.md`, "Peer measurement (`btest`)")
|
|
|
15
15
|
loss / direction against the CHR's own `/tool/bandwidth-test` status output
|
|
16
16
|
(CHR 7.23.1, `bun run test:integration`). Examples **4** (wrong-credentials) and
|
|
17
17
|
**5** (multi-connection TCP) are **designed but not yet gated** — the auth-reject
|
|
18
|
-
path is covered by the loopback unit test, and
|
|
19
|
-
|
|
18
|
+
path is covered by the loopback unit test, and example 5 is the **server-side**
|
|
19
|
+
secondary-accept (distinct from the now-gated **client** fan-out in example 11),
|
|
20
|
+
still a documented follow-up — so they are not part of the asserted run.
|
|
20
21
|
- **Gated `CHR-passed` (client cell): centrs client → CHR bandwidth-server** —
|
|
21
22
|
examples **6** (TCP receive) and **8** (EC-SRP5 client role + wrong-password
|
|
22
23
|
reject) are *also* asserted directly against a real RouterOS
|
|
23
24
|
`/tool/bandwidth-server`, over a host→guest `tcp:2000` forward
|
|
24
25
|
(`test/integration/btest-client.test.ts`, CHR 7.23.1). This is what makes the
|
|
25
26
|
**client** cell `CHR-passed`: centrs's EC-SRP5 **client proof** is verified by
|
|
26
|
-
RouterOS's own server verifier.
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
RouterOS's own server verifier. Example **11** (TCP **multi-connection**
|
|
28
|
+
fan-out), a TCP `direction=both` #85 regression guard, and **UDP receive/both**
|
|
29
|
+
(#88 — the server→client return over the guest→host SLIRP gateway) are gated in
|
|
30
|
+
the same suite.
|
|
29
31
|
- **Unit / loopback (client cell + codec)** — examples 6–10. centrs client ↔
|
|
30
32
|
centrs server on `127.0.0.1` with injected sockets; the EC-SRP5 both-roles math
|
|
31
33
|
and the pre-socket option-grammar rejects (`test/unit/btest.test.ts`). These are
|
|
@@ -113,12 +115,13 @@ contains a `transport/auth-failed` entry (the EC-SRP5 proof did not verify) and
|
|
|
113
115
|
`data.sessions` is empty — no session opened, no throughput. The CHR side reports
|
|
114
116
|
an authentication failure.
|
|
115
117
|
|
|
116
|
-
### 5. Multi-connection TCP transmit
|
|
118
|
+
### 5. Multi-connection TCP transmit (server-side accept)
|
|
117
119
|
|
|
118
|
-
> *Designed, not yet gated* — the server
|
|
119
|
-
> `
|
|
120
|
-
>
|
|
121
|
-
>
|
|
120
|
+
> *Designed, not yet gated* — this is the **server-side** fan-out: centrs's
|
|
121
|
+
> `btest server` accepting parallel secondary joins from a client. The session
|
|
122
|
+
> token is negotiated but centrs's server does not yet serve secondary TCP joins.
|
|
123
|
+
> Distinct from the **client** fan-out (example 11), which **is** implemented and
|
|
124
|
+
> gated. Tracked as a follow-up (#100); not part of the asserted run.
|
|
122
125
|
|
|
123
126
|
```bash
|
|
124
127
|
centrs btest server --authenticate=false --bind 0.0.0.0 --duration 20s --format json
|
|
@@ -188,3 +191,25 @@ centrs btest client $SRV --protocol udp --local-udp-tx-size 99999
|
|
|
188
191
|
`ok: false`, `error.code = "validation/option"` (UDP size must be `28..64000`), no
|
|
189
192
|
socket opened. The same gate rejects `connection-count` outside `1..255`,
|
|
190
193
|
`interval` outside `20ms..5s`, and (server) `max-sessions` outside `1..1000`.
|
|
194
|
+
|
|
195
|
+
## centrs client TCP multi-connection (gated; client cell)
|
|
196
|
+
|
|
197
|
+
### 11. Multi-connection TCP receive fan-out
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
centrs btest client <router> --protocol tcp --direction receive --connection-count 4 --duration 4s --format json
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Against a real RouterOS `/tool/bandwidth-server` (`authenticate=no`), centrs reads
|
|
204
|
+
the session token from the primary's OK and opens the 3 extra TCP data
|
|
205
|
+
connections, each presenting the grounded join `[token:u16 BE][0x02][0 …]`. The
|
|
206
|
+
summary is `ok: true` with `data.activeConnections: 4` and non-zero aggregate
|
|
207
|
+
throughput — real RouterOS accepted all 3 secondary joins and data flowed on every
|
|
208
|
+
connection (the per-connection drive is also asserted deterministically by the
|
|
209
|
+
loopback unit test). The *throughput increase* multiple streams provide is a
|
|
210
|
+
high-latency/WAN-link property and is **not** observable over the near-zero-latency
|
|
211
|
+
SLIRP loopback (a single TCP stream already saturates it), so the gate asserts the
|
|
212
|
+
fan-out itself, not a higher number. Gated in
|
|
213
|
+
`test/integration/btest-client.test.ts` (CHR 7.23.1). An **authenticated**
|
|
214
|
+
`--connection-count > 1` run instead stays single-stream (`activeConnections: 1`)
|
|
215
|
+
and carries a `routeros/btest-connection-count-single-stream` warning.
|