Skip to content

feat(web): realtime WebSocket sync for web editor#10

Open
ZenithDevHQ wants to merge 6 commits into
mainfrom
feature/realtime-websocket-editor
Open

feat(web): realtime WebSocket sync for web editor#10
ZenithDevHQ wants to merge 6 commits into
mainfrom
feature/realtime-websocket-editor

Conversation

@ZenithDevHQ

Copy link
Copy Markdown
Contributor

Summary

Adds bidirectional realtime WebSocket sync between the HyperPerms plugin and the web editor, enabling live permission editing with instant feedback. Changes made in the web editor are applied to the server in real-time, and changes made via commands or other sources are reflected back to the editor immediately.

Architecture

The plugin connects to a Cloudflare Durable Object (deployed separately) via WebSocket, which acts as a relay between the plugin and the web editor. This gives us:

  • Sub-second change propagation in both directions
  • No polling overhead
  • Connection resilience with automatic reconnect
  • Graceful fallback to REST when WebSocket is unavailable

What's included

Event System Additions

  • TrackCreateEvent, TrackDeleteEvent, TrackModifyEvent - new track lifecycle events following the existing PRE/POST pattern used by GroupCreateEvent/GroupDeleteEvent
  • EventBus integration in TrackManagerImpl to fire events on track CRUD operations
  • New TRACK_CREATE, TRACK_DELETE, TRACK_MODIFY entries in EventType enum

WebSocket Echo Prevention

  • ChangeApplier.applyChangesFromWebSocket() wraps change application with a ThreadLocal flag
  • EventBus listeners can check ChangeApplier.isApplyingFromWebSocket() to skip re-broadcasting changes that originated from the WebSocket relay

WebSocket Client (WebSocketSessionClient)

  • Built on java.net.http.HttpClient.newWebSocketBuilder(), reuses the existing HttpClient from WebEditorService
  • Subscribes to all EventBus events (permission, group, user, track changes) and converts them to WebSocket ops
  • Handles incoming batch.apply messages: deserializes ops into Change objects, applies via ChangeApplier, returns success/failure counts with undo ID
  • Handles session.sync requests by serializing current state via SessionData.fromHyperPerms()
  • Auto-reconnect with exponential backoff (1s, 2s, 4s... configurable max delay and max attempts)
  • Ping/pong keepalive with configurable timeout (reconnects if no ping received within threshold)

Service Integration

  • WebEditorService gains connectWebSocket(), disconnectWebSocket(), getActiveWsClient() lifecycle methods
  • SessionCreateResponse now includes the wsUrl field returned by the API
  • Automatic WS connection after successful session creation (when enabled in config)

Command Updates

  • EditorSubCommand: displays "Live connection established" when WS connects after session creation
  • ApplySubCommand: sends batch.apply over WebSocket when connected, falls back to REST otherwise

Configuration

  • websocketEnabled (default: true) - master toggle for WebSocket features
  • websocketReconnectMaxAttempts (default: 10) - max reconnect attempts before giving up
  • websocketReconnectMaxDelaySeconds (default: 30) - cap on exponential backoff delay
  • websocketPingTimeoutSeconds (default: 90) - time without ping before triggering reconnect

Shutdown

  • HyperPerms.disable() calls webEditorService.disconnectWebSocket() for clean shutdown

Files Changed

File Change
TrackCreateEvent.java New - track creation event with PRE/POST phases
TrackDeleteEvent.java New - track deletion event with PRE/POST phases
TrackModifyEvent.java New - track modification event
HyperPermsEvent.java Add TRACK_CREATE/DELETE/MODIFY to EventType
TrackManagerImpl.java Fire track events on CRUD, accept EventBus
ChangeApplier.java Add ThreadLocal echo prevention for WS
WebSocketSessionClient.java New - full WS client with event bridging
WebEditorService.java Add WS lifecycle management
SessionCreateResponse.java Add wsUrl field
WebEditorConfig.java Add WS config fields
HyperPermsConfig.java Add WS config getters
EditorSubCommand.java Show WS connection status
ApplySubCommand.java WS-first apply with REST fallback
HyperPerms.java WS cleanup on disable

Test Plan

  • Create a web editor session and verify WebSocket connects (Live connection established message in console)
  • Make a permission change in the web editor and verify it applies on the server
  • Make a permission change via command and verify it appears in the web editor
  • Test batch apply: queue multiple changes in batch mode, apply, verify all succeed
  • Test undo: apply changes, use undo, verify rollback
  • Test reconnection: kill the WS connection, verify auto-reconnect with backoff
  • Test fallback: set websocketEnabled: false, verify REST apply still works
  • Test shutdown: disable the plugin, verify WS disconnects cleanly
  • Verify no echo loops: changes from WS don't fire events back to WS

Design for two-way realtime sync between the web editor and plugin
using Cloudflare Durable Objects as a WebSocket relay. Covers message
protocol, conflict detection, undo history, and three-codebase changes.
- Add TRACK_CREATE, TRACK_DELETE, TRACK_MODIFY to EventType enum
- Create TrackCreateEvent with PRE/POST pattern (matching GroupCreateEvent)
- Create TrackDeleteEvent with PRE/POST pattern (matching GroupDeleteEvent)
- Create TrackModifyEvent for track group list changes
- Add EventBus to TrackManagerImpl constructor, fire events on CRUD
- Pass eventBus to TrackManagerImpl in HyperPerms.enable()
Adds a ThreadLocal flag and applyChangesFromWebSocket() method so
EventBus listeners can detect when changes originate from a WebSocket
message and avoid firing events back to the relay.
- Add nullable wsUrl field to SessionCreateResponse
- Update WebEditorService.createSession() to extract wsUrl from JSON
Add WebSocketSessionClient for bidirectional event bridging between
the Minecraft plugin and the web editor via Cloudflare Durable Objects.
Includes auto-reconnect with exponential backoff, ping/pong keepalive,
batch.apply handling, session.sync, and EventBus subscription for all
permission/group/track/user change events.

Integrate WS lifecycle into WebEditorService, add config options
(websocketEnabled, reconnect params, ping timeout), update editor/apply
commands for WS-first with REST fallback, and add shutdown cleanup.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant