5.2 KiB
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:
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:
{
"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 WebSocketunmount(): 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
- Backend: session cookie persistence in AppState + login.rs
- Backend: kvm.rs with three endpoints, test with curl
- Frontend: shell.ts with sidebar navigation
- Frontend: refactor console.ts → pages/console.ts with mount/unmount
- Frontend: pages/ports.ts wired to API
- Frontend: port switcher dropdown in console toolbar
Verification
cargo test && cargo clippypassnpx tsc --noEmitpassescurl /api/kvm/portsreturns correct JSON matching device statecurl -X POST /api/kvm/switch -d '{"port":0}'switches the active portcurl -X PUT /api/kvm/portswith 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