Conversation
With the Serial Console extension loaded, the UART on the extension port can now also be reached over the network, in one of two modes: - ser2net: a TCP listener (default port 2217), either raw or telnet with RFC 2217 so clients such as pyserial's rfc2217:// can set the baud rate, data bits, parity and stop bits. A client's line settings last only for its session. IAC BREAK sends a serial break. There is no authentication, and the UI says so. The listener honours the loopback-only setting. - web: an authenticated WebSocket at /serial/ws (the usual auth cookie, same-origin only) behind a standalone full-page console at /serial, so the UART is usable without a WebRTC KVM session. Both modes go through the existing SerialMux, which stays the only reader and writer of /dev/ttyS3. UART reads fan out to network clients through a hub that never blocks the reader; a client that falls behind by 256 reads is disconnected. Concurrent clients are capped (1 by default, up to 8). getSerialNetworkStatus reports the listener, errors and connected clients, and Prometheus exports client counts and relayed bytes. The settings live in serialSettings.json with the other Serial Console settings; older files get the new defaults (disabled). Also: - The stored Serial Console settings are now applied at boot when the extension is loaded, not when the UI next opens it. - A missing serialSettings.json no longer fails getSerialSettings. - SerialMux.Enqueue no longer blocks forever once the mux is closed. Refs jetkvm#1520 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01C3BNwaCJdCFHEuH7EZcR7j
A collector reports the extension port UART's state at scrape time:
- jetkvm_serial_port_open{device}
- jetkvm_serial_port_info{device,baud_rate,data_bits,parity,stop_bits,extension}
- jetkvm_serial_port_baud_rate{device}
- jetkvm_serial_network_info{mode,protocol,listen_address}
- jetkvm_serial_network_up{mode}
- jetkvm_serial_network_max_clients
go.bug.st/serial can't read back the port's mode, so every open, close
and SetMode now goes through setSerialPortMode and a small tracker.
The metrics then show what the port is actually running at, including
settings an RFC 2217 client applied for its session, and the info
series is dropped rather than left stale when the port closes.
setSerialPortMode also checks for a port that failed to open, which
the ATX and DC extension mounts did not.
The collector test uses client_golang's testutil, which adds
kylelemons/godebug as an indirect module requirement (already in
go.sum).
Refs jetkvm#1520
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C3BNwaCJdCFHEuH7EZcR7j
Owner
Author
|
Superceded by jetkvm#1660 to upstream |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes jetkvm#1520
Summary
With the Serial Console extension loaded, the extension port UART (
/dev/ttyS3) can now be reached over the network. A new Network Access setting has three options: Disabled (the default), ser2net (TCP) or Web console. This turns a JetKVM, or a rack of them, into a serial console server without SSH/developer mode or an external daemon.ser2net mode: a native Go TCP listener. The port is configurable (default 2217), and so is the protocol:
socat -,raw,echo=0 tcp:<ip>:2217).IAC BRKsends a real serial break (SysRq). RFC 2217 clients such as pyserial'srfc2217://can set baud rate, data bits, parity and stop bits for the length of their session. The configured settings come back when they disconnect.Web mode:
GET /serial/wssits behind the existing auth middleware and cookie. It uses the library's default same-origin check (noInsecureSkipVerify), so another site can't use the auth cookie to reach the UART. Frames carry raw UART bytes both ways. A new device-only route,/serial, is a full-page xterm console on top of it, so the UART works in a plain browser tab without a WebRTC KVM session. The extension panel has an "Open Web Console" button.Shared design
SerialMux, which stays the only reader and writer of the port. Network clients, the in-session WebRTC console and quick buttons don't race on the fd (this answers the concurrency question in the issue). Network input is echoed into the in-session console like typed input.getSerialNetworkStatus, reports whether it is running, the listen address, any bind error and the connected clients. The UI polls it.serialSettings.jsonwith the other Serial Console settings. Older files get the defaults, so the feature stays disabled.Prometheus metrics (on the existing
/metricsendpoint)jetkvm_serial_port_opendevicejetkvm_serial_port_infodevice,baud_rate,data_bits,parity,stop_bits,extensionjetkvm_serial_port_baud_ratedevicejetkvm_serial_network_infomode,protocol,listen_addressjetkvm_serial_network_upmodejetkvm_serial_network_max_clientsjetkvm_serial_network_clientstransportjetkvm_serial_network_bytes_totaltransport,directionThe port and network metrics come from a collector that runs at scrape time.
go.bug.st/serialcan't read back a port's mode, so every open, close andSetModenow goes throughsetSerialPortModeand a small tracker. The metrics then show the settings the port is actually running at, including a session-only RFC 2217 change, and the info series disappears rather than going stale when the port closes. Example fleet query:count by (mode) (jetkvm_serial_network_up == 1).Small fixes this change needs
serialSettings.jsonno longer returns an error fromgetSerialSettings; the defaults apply.SerialMux.Enqueueno longer blocks forever once the mux has been closed./dev/ttyS3failed to open, instead of panicking. This also covers the ATX and DC extension mounts.Not included (possible follow-ups): mDNS/DNS-SD advertisement of the ser2net port for fleet discovery, and RFC 2217 NOTIFY-LINESTATE/MODEMSTATE. The extension port has no modem lines, so SET-CONTROL requests are acknowledged but have no effect.
How this answers the issue discussion
microcom(@justarandomgeek):jetkvm_appalready holds the fd and wins mostread()s, so a second process only sees fragments. This PR doesn't add another reader; network clients subscribe toSerialMux's one reader, so every client gets every byte.SerialMuxbeforeConsoleBroker, so ser2net and web clients get the raw byte stream with no line splitting,RX:/TX:labels or control-character normalisation. Terminals,expectscripts and ANSI/curses output work unchanged. The broker still feeds the in-session WebRTC console as before.Testing
serial_server_test.goandserial_metrics_test.go(no build tag, so they run on amd64 CI) cover:The server tests pass 30 runs in a row under
-race.go vet,golangci-lint(repo config) → 0 issues.UI:
tsc,oxlint(0 new warnings),oxfmt.Smoke-tested
/serialin Chromium against a mock backend: it connects, shows UART output, and typed input reaches the backend and is echoed back./dev/ttyS3, andmake test_e2ehasn't been run.Checklist
make test_e2elocally and passed. Not run (needs a device).🤖 Generated with Claude Code
https://claude.ai/code/session_01C3BNwaCJdCFHEuH7EZcR7j