Files
blekin/doc/plan/implementation-feature-port-mapping.md

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

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 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