- Fix nickname index stale pointer during session reconnection
- Reset LastActive for all emergency promotions to prevent cascade timeouts
- Bypass rate limits when no primary exists to prevent system deadlock
- Replace manual mutex with atomic.Int32 for session counter (fixes race condition)
- Implement collect-then-delete pattern for safe map iteration
- Reduce logging verbosity for routine cleanup operations
Root cause: Session pointer inconsistency during RPC/HID message processing.
The RPC and HID queue handlers were fetching a fresh session copy from the
session manager instead of using the original session pointer. This caused
permission checks to fail when the session was promoted to primary, because
the Mode field was updated in the manager's copy but not reflected in the
queue handler's copy.
Changes:
- Revert RPC queue handler to use original session pointer (webrtc.go:320)
- Revert HID queue handler to use original session pointer (webrtc.go:196)
- Add debug logging for permission check failures (hidrpc.go:31-34, 57-61, 71-75)
This ensures that when a session's Mode is updated in the session manager,
the change is immediately visible to all message handlers, preventing the
race condition where mouse/keyboard input would be silently dropped due to
HasPermission() checks failing on stale session state.
The permission logging will help diagnose any remaining edge cases where
input is blocked unexpectedly.
The jiggler sends keep-alive packets every 50ms to prevent keyboard
auto-release, but wasn't updating the session's LastActive timestamp.
This caused the backend to timeout and demote the primary session after
5 minutes (default primaryTimeout), even with active jiggler.
Primary fix:
- Add UpdateLastActive call to handleHidRPCKeepressKeepAlive() in hidrpc.go
- Ensures jiggler packets prevent session timeout
Defensive enhancement:
- Add WebSocket fallback for emergency promotion signals in session_manager.go
- Store WebSocket reference in Session struct (webrtc.go)
- Handle connectionModeChanged via WebSocket in devices.$id.tsx
- Provides reliable signaling when WebRTC data channel is stale
Changes:
- Add permission checks before making getVideoState, getKeyboardLedState,
and getKeyDownState RPC calls to prevent rejected requests for sessions
without VIDEO_VIEW permission
- Fix infinite loop issue by excluding hasPermission from useEffect
dependency arrays (functions recreated on render cause infinite loops)
- Increase RPC rate limit from 100 to 500 per second to support 10+
concurrent sessions with broadcasts and state updates
This eliminates console spam from permission denied errors and log spam
from continuous RPC calls, while improving multi-session performance.
The session manager had backwards logic that prevented sessions from
restoring their primary status when reconnecting within the grace period.
This caused browser refreshes to demote primary sessions to observers.
Changes:
- Fix conditional in AddSession to allow primary restoration within grace
- Remove excessive debug logging throughout session manager
- Clean up unused decrActiveSessions function
- Remove unnecessary leading newline in NewSessionManager
- Update lastPrimaryID handling to support WebRTC reconnections
- Preserve grace periods during transfers to allow browser refreshes
The fix ensures that when a primary session refreshes their browser:
1. RemoveSession adds a grace period entry
2. New connection checks wasWithinGracePeriod and wasPreviouslyPrimary
3. Session correctly reclaims primary status
Blacklist system prevents demoted sessions from immediate re-promotion
while grace periods allow legitimate reconnections.
The previous limit of 20 RPC/second per session was too aggressive for
multi-session scenarios. During normal operation with multiple sessions,
legitimate RPC calls would frequently hit the rate limit, especially
during page refreshes or reconnections when sessions make bursts of calls
like getSessions, getPermissions, getLocalVersion, and getVideoState.
Increased the limit to 100 RPC/second per session, which still provides
DoS protection while accommodating legitimate multi-session usage patterns.
Address all linting warnings and errors in both backend and frontend code:
**Go (golangci-lint):**
- Add error checking for ignored return values (errcheck)
- Remove unused RPC functions (unused)
- Fix import formatting (goimports)
**TypeScript/React (eslint):**
- Replace all 'any' and 'Function' types with proper type definitions
- Add RpcSendFunction type for consistent JSON-RPC callback signatures
- Fix React Hook exhaustive-deps warnings by adding missing dependencies
- Wrap functions in useCallback where needed to stabilize dependencies
- Remove unused variables and imports
- Remove empty code blocks
- Suppress exhaustive-deps warnings where intentional (with comments)
All linting now passes with 0 errors and 0 warnings.
* feat: release keyPress automatically
* send keepalive when pressing the key
* remove logging
* clean up logging
* chore: use unreliable channel to send keepalive events
* chore: use ordered unreliable channel for pointer events
* chore: adjust auto release key interval
* chore: update logging for kbdAutoReleaseLock
* chore: update comment for KEEPALIVE_INTERVAL
* fix: should cancelAutorelease when pressed is true
* fix: handshake won't happen if webrtc reconnects
* chore: add trace log for writeWithTimeout
* chore: add timeout for KeypressReport
* chore: use the proper key to send release command
* refactor: simplify HID RPC keyboard input handling and improve key state management
- Updated `handleHidRPCKeyboardInput` to return errors directly instead of keys down state.
- Refactored `rpcKeyboardReport` and `rpcKeypressReport` to return errors instead of states.
- Introduced a queue for managing key down state updates in the `Session` struct to prevent input handling stalls.
- Adjusted the `UpdateKeysDown` method to handle state changes more efficiently.
- Removed unnecessary logging and commented-out code for clarity.
* refactor: enhance keyboard auto-release functionality and key state management
* fix: correct Windows default auto-repeat delay comment from 1ms to 1s
* refactor: send keypress as early as possible
* refactor: replace console.warn with console.info for HID RPC channel events
* refactor: remove unused NewKeypressKeepAliveMessage function from HID RPC
* fix: handle error in key release process and log warnings
* fix: log warning on keypress report failure
* fix: update auto-release keyboard interval to 225
* refactor: enhance keep-alive handling and jitter compensation in HID RPC
- Implemented staleness guard to ignore outdated keep-alive packets.
- Added jitter compensation logic to adjust timer extensions based on packet arrival times.
- Introduced new methods for managing keep-alive state and reset functionality in the Session struct.
- Updated auto-release delay mechanism to use dynamic durations based on keep-alive timing.
- Adjusted keep-alive interval in the UI to improve responsiveness.
* gofmt
* clean up code
* chore: use dynamic duration for scheduleAutoRelease
* Use harcoded timer reset value for now
* fix: prevent nil pointer dereference when stopping timers in Close method
* refactor: remove nil check for kbdAutoReleaseTimers in DelayAutoReleaseWithDuration
* refactor: optimize dependencies in useHidRpc hooks
* refactor: streamline keep-alive timer management in useKeyboard hook
* refactor: clarify comments in useKeyboard hook for resetKeyboardState function
* refactor: reduce keysDownStateQueueSize
* refactor: close and reset keysDownStateQueue in newSession function
* chore: resolve conflicts
* resolve conflicts
---------
Co-authored-by: Adam Shiervani <adam.shiervani@gmail.com>
* chore/Deprecate browser mount
No longer supported.
* Remove device-side go code
* Removed diskChannel and localFile
* Removed RemoteVirtualMediaState.WebRTC
Also removed dead go code (to make that lint happy!)
Remove LED sync source option and add keypress reporting while still working with devices that haven't been upgraded
We return the modifiers as the valid bitmask so that the VirtualKeyboard and InfoBar can represent the correct keys as down. This is important when we have strokes like Left-Control + Right-Control + Keypad-1 (used in switching KVMs and such).
Fix handling of modifier keys in client and also removed the extraneous resetKeyboardState.
Manage state to eliminate rerenders by judicious use of useMemo.
Centralized keyboard layout and localized display maps
Move keyboardOptions to useKeyboardLayouts
Added translations for display maps.
Add documentation on the legacy support.
Return the KeysDownState from keyboardReport
Clear out the hidErrorRollOver once sent to reset the keyboard to nothing down.
Handles the returned KeysDownState from keyboardReport
Now passes all logic through handleKeyPress.
If we get a state back from a keyboardReport, use it and also enable keypressReport because we now know it's an upgraded device.
Added exposition on isoCode management
Fix de-DE chars to reflect German E2 keyboard.
https://kbdlayout.info/kbdgre2/overview+virtualkeys
Ran go modernize
Morphs Interface{} to any
Ranges over SplitSeq and FieldSeq for iterating splits
Used min for end calculation remote_mount.Read
Used range 16 in wol.createMagicPacket
DID NOT apply the Omitempty cleanup.
Strong typed in the typescript realm.
Cleanup react state management to enable upgrading Zustand
* feat(cloud): Use Websocket signaling in cloud mode
* refactor: Enhance WebRTC signaling and connection handling
* refactor: Improve WebRTC connection management and logging in KvmIdRoute
* refactor: Update PeerConnectionDisconnectedOverlay to use Card component for better UI structure
* refactor: Standardize metric naming and improve websocket logging
* refactor: Rename WebRTC signaling functions and update deployment script for debug version
* fix: Handle error when writing new ICE candidate to WebRTC signaling channel
* refactor: Rename signaling handler function for clarity
* refactor: Remove old http local http endpoint
* refactor: Improve metric help text and standardize comparison operator in KvmIdRoute
* chore(websocket): use MetricVec instead of Metric to store metrics
* fix conflicts
* fix: use wss when the page is served over https
* feat: Add app version header and update WebRTC signaling endpoint
* fix: Handle error when writing device metadata to WebRTC signaling channel
---------
Co-authored-by: Siyuan Miao <i@xswan.net>