Class: TUI::CableClient
- Inherits:
-
Object
- Object
- TUI::CableClient
- Defined in:
- lib/tui/cable_client.rb
Overview
Action Cable WebSocket client for connecting the TUI to the brain server. Runs the WebSocket connection in a background thread and exposes a thread-safe message queue for the TUI render loop to drain.
Implements the actioncable-v1-json protocol: subscribe to a SessionChannel, receive event broadcasts, and send user input via the speak action.
Automatically reconnects with exponential backoff when the connection drops unexpectedly. Detects stale connections via Action Cable ping heartbeat monitoring.
Constant Summary collapse
- DISCONNECT_TIMEOUT =
seconds to wait for WebSocket thread to finish
2- POLL_INTERVAL =
seconds between connection status checks
0.1- CONNECTION_TIMEOUT =
seconds to wait for the connecting state to advance
10- MAX_RECONNECT_ATTEMPTS =
10- BACKOFF_BASE =
initial backoff delay in seconds
1.0- BACKOFF_CAP =
maximum backoff delay
30.0- PING_STALE_THRESHOLD =
seconds without ping before connection is stale
6.0
Instance Attribute Summary collapse
-
#host ⇒ String
readonly
Brain server host:port.
-
#reconnect_attempt ⇒ Integer
readonly
Current reconnection attempt (0 when connected).
-
#session_id ⇒ Integer
readonly
Current session ID.
-
#status ⇒ Symbol
readonly
Connection status (:disconnected, :connecting, :connected, :subscribed, :reconnecting).
Instance Method Summary collapse
-
#change_view_mode(mode) ⇒ void
Requests the brain to change the session’s view mode.
-
#connect ⇒ Object
Opens the WebSocket connection in a background thread.
-
#create_session ⇒ Object
Requests the brain to create a new session and switch to it.
-
#disconnect ⇒ Object
Closes the WebSocket connection and cleans up the background thread.
-
#drain_messages ⇒ Array<Hash>
Drains all pending messages from the queue (non-blocking).
-
#initialize(host:, session_id:) ⇒ CableClient
constructor
A new instance of CableClient.
-
#list_sessions(limit: 10) ⇒ Object
Requests a list of recent sessions from the brain.
-
#resubscribe(new_session_id) ⇒ Object
deprecated
Deprecated.
Use #create_session or #switch_session instead. The server now handles stream switching via the session protocol.
-
#speak(content) ⇒ Object
Sends user input to the brain for processing.
-
#switch_session(session_id) ⇒ Object
Requests the brain to switch to an existing session.
-
#update_session_id(new_id) ⇒ Object
Updates the local session ID reference after a server-side session switch.
Constructor Details
#initialize(host:, session_id:) ⇒ CableClient
Returns a new instance of CableClient.
48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/tui/cable_client.rb', line 48 def initialize(host:, session_id:) @host = host @session_id = session_id @status = :disconnected @message_queue = Thread::Queue.new @mutex = Mutex.new @ws = nil @ws_thread = nil @intentional_disconnect = false @reconnect_attempt = 0 @last_ping_at = nil @connection_generation = 0 end |
Instance Attribute Details
#host ⇒ String (readonly)
Returns brain server host:port.
35 36 37 |
# File 'lib/tui/cable_client.rb', line 35 def host @host end |
#reconnect_attempt ⇒ Integer (readonly)
Returns current reconnection attempt (0 when connected).
44 45 46 |
# File 'lib/tui/cable_client.rb', line 44 def reconnect_attempt @reconnect_attempt end |
#session_id ⇒ Integer (readonly)
Returns current session ID.
38 39 40 |
# File 'lib/tui/cable_client.rb', line 38 def session_id @session_id end |
#status ⇒ Symbol (readonly)
Returns connection status (:disconnected, :connecting, :connected, :subscribed, :reconnecting).
41 42 43 |
# File 'lib/tui/cable_client.rb', line 41 def status @status end |
Instance Method Details
#change_view_mode(mode) ⇒ void
This method returns an undefined value.
Requests the brain to change the session’s view mode. The server broadcasts view_mode_changed to all clients on the session, followed by the re-decorated viewport.
109 110 111 |
# File 'lib/tui/cable_client.rb', line 109 def change_view_mode(mode) send_action("change_view_mode", {"view_mode" => mode}) end |
#connect ⇒ Object
Opens the WebSocket connection in a background thread. The connection subscribes to the session channel automatically after receiving the Action Cable welcome message. Reconnects automatically on unexpected disconnection.
66 67 68 69 70 71 72 |
# File 'lib/tui/cable_client.rb', line 66 def connect @mutex.synchronize do @intentional_disconnect = false @status = :connecting end @ws_thread = Thread.new { run_websocket_loop } end |
#create_session ⇒ Object
Requests the brain to create a new session and switch to it. The server responds with a session_changed message followed by history.
83 84 85 |
# File 'lib/tui/cable_client.rb', line 83 def create_session send_action("create_session", {}) end |
#disconnect ⇒ Object
Closes the WebSocket connection and cleans up the background thread. Prevents automatic reconnection.
147 148 149 150 151 152 153 154 |
# File 'lib/tui/cable_client.rb', line 147 def disconnect @mutex.synchronize do @intentional_disconnect = true @status = :disconnected end @ws&.close @ws_thread&.join(DISCONNECT_TIMEOUT) end |
#drain_messages ⇒ Array<Hash>
Drains all pending messages from the queue (non-blocking). Call this from the TUI render loop to process incoming events.
124 125 126 127 128 129 130 131 132 |
# File 'lib/tui/cable_client.rb', line 124 def = [] loop do << @message_queue.pop(true) rescue ThreadError break end end |
#list_sessions(limit: 10) ⇒ Object
Requests a list of recent sessions from the brain. The server responds with a sessions_list message.
99 100 101 |
# File 'lib/tui/cable_client.rb', line 99 def list_sessions(limit: 10) send_action("list_sessions", {"limit" => limit}) end |
#resubscribe(new_session_id) ⇒ Object
Use #create_session or #switch_session instead. The server now handles stream switching via the session protocol.
Unsubscribes from the current session and subscribes to a new one.
139 140 141 142 143 |
# File 'lib/tui/cable_client.rb', line 139 def resubscribe(new_session_id) unsubscribe_current @mutex.synchronize { @session_id = new_session_id } subscribe end |
#speak(content) ⇒ Object
Sends user input to the brain for processing.
77 78 79 |
# File 'lib/tui/cable_client.rb', line 77 def speak(content) send_action("speak", {"content" => content}) end |
#switch_session(session_id) ⇒ Object
Requests the brain to switch to an existing session. The server responds with a session_changed message followed by history.
91 92 93 |
# File 'lib/tui/cable_client.rb', line 91 def switch_session(session_id) send_action("switch_session", {"session_id" => session_id}) end |
#update_session_id(new_id) ⇒ Object
Updates the local session ID reference after a server-side session switch.
116 117 118 |
# File 'lib/tui/cable_client.rb', line 116 def update_session_id(new_id) @mutex.synchronize { @session_id = new_id } end |