doc: port mapping implementation planning
This commit is contained in:
121
doc/plan/implementation-feature-port-mapping.md
Normal file
121
doc/plan/implementation-feature-port-mapping.md
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
# KVM port configuration and switching
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
The Belkin OmniView fronts an Avocent KVM switch with up to 16 ports. The legacy web interface at `http://10.3.0.130` allows port naming, hotkey assignment, visibility toggling, and active port switching. Users currently need to visit that interface separately. We want blekin to fully replace it — starting with port management, with a navigation structure that supports adding more settings pages later.
|
||||||
|
|
||||||
|
## Belkin device API (from HTML form inspection)
|
||||||
|
|
||||||
|
**GET /kvm.asp** — returns HTML form with current port config:
|
||||||
|
- `ECG_kvm_nr_ports`: port count (1,2,4,8,12,16,24,32,48,64)
|
||||||
|
- `ECG_key_pause_duration`: ms (default 100)
|
||||||
|
- Per port N (0-indexed): `ECG_kvm_portname_N`, `ECG_kvm_hotkey_N`, `ECG_kvm_show_in_rc_N`
|
||||||
|
- `kvm_active_port_0`: currently selected port
|
||||||
|
|
||||||
|
**POST /kvm.asp** — save port config (same fields + `action_apply=Apply`)
|
||||||
|
|
||||||
|
**POST /home2.asp** — switch active port: `kvm_active_port_0=<0-15>&action_switch_0=Switch`
|
||||||
|
|
||||||
|
All requests require `pp_session_id` cookie.
|
||||||
|
|
||||||
|
## Changes
|
||||||
|
|
||||||
|
### Backend: persist session cookie
|
||||||
|
|
||||||
|
Modify `AppState` in `main.rs` to hold the device session cookie:
|
||||||
|
```rust
|
||||||
|
pub session_cookie: Arc<tokio::sync::RwLock<Option<String>>>,
|
||||||
|
```
|
||||||
|
|
||||||
|
Update `login.rs` to store the cookie into shared state after successful auth.
|
||||||
|
|
||||||
|
### Backend: new REST endpoints (`crates/ericrfb-proxy/src/kvm.rs`)
|
||||||
|
|
||||||
|
| Endpoint | Method | Purpose |
|
||||||
|
|----------|--------|---------|
|
||||||
|
| `/api/kvm/ports` | GET | Fetch port config (scrape kvm.asp, return JSON) |
|
||||||
|
| `/api/kvm/ports` | PUT | Save port config (build form, POST to kvm.asp) |
|
||||||
|
| `/api/kvm/switch` | POST | Switch active port (POST to home2.asp) |
|
||||||
|
|
||||||
|
**GET /api/kvm/ports response:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"port_count": 16,
|
||||||
|
"key_pause_duration": 100,
|
||||||
|
"active_port": 0,
|
||||||
|
"ports": [
|
||||||
|
{ "index": 0, "name": "oolon", "hotkey": "", "show_in_rc": true },
|
||||||
|
...
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
HTML scraping: simple string/regex matching on the predictable firmware HTML (extract `value="..."` from named inputs, `selected` from dropdowns, `checked` from checkboxes).
|
||||||
|
|
||||||
|
### Frontend: app shell with navigation (`crates/ericrfb-frontend/src/shell.ts`)
|
||||||
|
|
||||||
|
After login, render a shell layout:
|
||||||
|
```
|
||||||
|
+----------+----------------------------------+
|
||||||
|
| sidebar | content area |
|
||||||
|
| | |
|
||||||
|
| Console | (active page rendered here) |
|
||||||
|
| Ports | |
|
||||||
|
| | |
|
||||||
|
+----------+----------------------------------+
|
||||||
|
```
|
||||||
|
|
||||||
|
Each page module exports `mount(container)` and `unmount()`. The shell swaps them on nav clicks. This pattern supports adding Virtual Media, Users, Device Settings etc. later without restructuring.
|
||||||
|
|
||||||
|
### Frontend: refactor console into page module
|
||||||
|
|
||||||
|
Move `console.ts` logic into a `pages/console.ts` with mount/unmount pattern:
|
||||||
|
- `mount(el, session)`: creates toolbar + canvas, connects WebSocket
|
||||||
|
- `unmount()`: tears down WebSocket, removes event listeners
|
||||||
|
|
||||||
|
Add port switcher `<select>` to the console toolbar (fetches port list from `/api/kvm/ports`, calls `/api/kvm/switch` on change, triggers reconnect).
|
||||||
|
|
||||||
|
### Frontend: port config page (`crates/ericrfb-frontend/src/pages/ports.ts`)
|
||||||
|
|
||||||
|
Editable table of ports with name, hotkey, show-in-console fields. Port count dropdown and key-pause input at the top. Save button PUTs to `/api/kvm/ports`. Each row has a Switch button that POSTs to `/api/kvm/switch`. Active port highlighted.
|
||||||
|
|
||||||
|
## Files
|
||||||
|
|
||||||
|
### New
|
||||||
|
| File | Purpose |
|
||||||
|
|------|---------|
|
||||||
|
| `crates/ericrfb-proxy/src/kvm.rs` | GET/PUT ports, POST switch, HTML scraping |
|
||||||
|
| `crates/ericrfb-frontend/src/shell.ts` | App shell, sidebar nav, page routing |
|
||||||
|
| `crates/ericrfb-frontend/src/pages/console.ts` | Console page (refactored from console.ts) |
|
||||||
|
| `crates/ericrfb-frontend/src/pages/ports.ts` | Port configuration page |
|
||||||
|
|
||||||
|
### Modified
|
||||||
|
| File | Changes |
|
||||||
|
|------|---------|
|
||||||
|
| `crates/ericrfb-proxy/src/main.rs` | session_cookie in AppState, new routes, `mod kvm` |
|
||||||
|
| `crates/ericrfb-proxy/src/login.rs` | Store cookie in shared state after auth |
|
||||||
|
| `crates/ericrfb-proxy/Cargo.toml` | Add `regex = "1"` |
|
||||||
|
| `crates/ericrfb-frontend/src/main.ts` | After login → mountShell() instead of startConsole() |
|
||||||
|
| `crates/ericrfb-frontend/src/login.ts` | Success callback → shell mount |
|
||||||
|
| `crates/ericrfb-frontend/src/style.css` | Shell layout, sidebar, ports page styles |
|
||||||
|
| `crates/ericrfb-frontend/src/console.ts` | Delete or re-export from pages/console.ts |
|
||||||
|
|
||||||
|
## Implementation order
|
||||||
|
|
||||||
|
1. Backend: session cookie persistence in AppState + login.rs
|
||||||
|
2. Backend: kvm.rs with three endpoints, test with curl
|
||||||
|
3. Frontend: shell.ts with sidebar navigation
|
||||||
|
4. Frontend: refactor console.ts → pages/console.ts with mount/unmount
|
||||||
|
5. Frontend: pages/ports.ts wired to API
|
||||||
|
6. Frontend: port switcher dropdown in console toolbar
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
- `cargo test && cargo clippy` pass
|
||||||
|
- `npx tsc --noEmit` passes
|
||||||
|
- `curl /api/kvm/ports` returns correct JSON matching device state
|
||||||
|
- `curl -X POST /api/kvm/switch -d '{"port":0}'` switches the active port
|
||||||
|
- `curl -X PUT /api/kvm/ports` with config JSON updates port names on device
|
||||||
|
- Frontend: navigate between Console and Ports pages without breaking WebSocket
|
||||||
|
- Frontend: switch port from console toolbar, console reconnects to new port
|
||||||
|
- Frontend: edit port names in Ports page, save, verify on device
|
||||||
Reference in New Issue
Block a user