Class: Smplkit::SharedWebSocket
- Inherits:
-
Object
- Object
- Smplkit::SharedWebSocket
- Defined in:
- lib/smplkit/ws.rb
Overview
Manages a single WebSocket connection to the app service event gateway.
A single SharedWebSocket instance is shared across all product modules (config, flags) within one Smplkit::Client. Product modules register listeners for specific event types; the shared connection dispatches incoming events to the appropriate listeners.
The connection runs on a dedicated SDK-owned thread; public methods are thread-safe and non-blocking.
The app service gateway protocol:
- Connect to +wss://app.<base_domain>/api/ws/v1/events?api_key={key}+
- Receive +{"type": "connected"}+ on success
- Receive events: +{"event": "config_changed", ...}+, etc.
- No subscribe message - the API key determines the account
- Heartbeat: server sends +"ping"+ (text), client responds with +"pong"+
NOTE: The actual WebSocket I/O is wired to async-websocket on a worker thread. The initial Ruby SDK release defers full live-update wiring to a follow-up because async-websocket interactions need integration testing against the real platform.
Constant Summary collapse
- BACKOFF_SCHEDULE =
[1, 2, 4, 8, 16, 32, 60].freeze
Instance Attribute Summary collapse
-
#connection_status ⇒ Object
readonly
Returns the value of attribute connection_status.
Instance Method Summary collapse
- #build_ws_url ⇒ Object
- #dispatch(event_name, data) ⇒ Object
-
#initialize(app_base_url:, api_key:, metrics: nil) ⇒ SharedWebSocket
constructor
A new instance of SharedWebSocket.
-
#mark_connected! ⇒ Object
Marked as connected for in-process testing without a real WS connection.
- #off(event_name, callback) ⇒ Object
- #on(event_name, &callback) ⇒ Object
- #start ⇒ Object
- #stop ⇒ Object
Constructor Details
#initialize(app_base_url:, api_key:, metrics: nil) ⇒ SharedWebSocket
Returns a new instance of SharedWebSocket.
30 31 32 33 34 35 36 37 38 |
# File 'lib/smplkit/ws.rb', line 30 def initialize(app_base_url:, api_key:, metrics: nil) @app_base_url = app_base_url @api_key = api_key @metrics = metrics @listeners = Concurrent::Hash.new { |h, k| h[k] = [] } @listeners_lock = Mutex.new @connection_status = "disconnected" @closed = false end |
Instance Attribute Details
#connection_status ⇒ Object (readonly)
Returns the value of attribute connection_status.
57 58 59 |
# File 'lib/smplkit/ws.rb', line 57 def connection_status @connection_status end |
Instance Method Details
#build_ws_url ⇒ Object
79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/smplkit/ws.rb', line 79 def build_ws_url url = @app_base_url.dup ws_url = if url.start_with?("https://") "wss://#{url[("https://".length)..]}" elsif url.start_with?("http://") "ws://#{url[("http://".length)..]}" else "wss://#{url}" end ws_url = ws_url.chomp("/") "#{ws_url}/api/ws/v1/events?api_key=#{@api_key}" end |
#dispatch(event_name, data) ⇒ Object
48 49 50 51 52 53 54 55 |
# File 'lib/smplkit/ws.rb', line 48 def dispatch(event_name, data) callbacks = @listeners_lock.synchronize { @listeners[event_name].dup } callbacks.each do |cb| cb.call(data) rescue StandardError => e Smplkit.debug("websocket", "listener for #{event_name} raised: #{e.class}: #{e.}") end end |
#mark_connected! ⇒ Object
Marked as connected for in-process testing without a real WS connection. Production wiring overrides this from the I/O thread once the gateway confirms the handshake.
62 63 64 |
# File 'lib/smplkit/ws.rb', line 62 def mark_connected! @connection_status = "connected" end |
#off(event_name, callback) ⇒ Object
44 45 46 |
# File 'lib/smplkit/ws.rb', line 44 def off(event_name, callback) @listeners_lock.synchronize { @listeners[event_name].delete(callback) } end |
#on(event_name, &callback) ⇒ Object
40 41 42 |
# File 'lib/smplkit/ws.rb', line 40 def on(event_name, &callback) @listeners_lock.synchronize { @listeners[event_name] << callback } end |
#start ⇒ Object
66 67 68 69 70 71 72 |
# File 'lib/smplkit/ws.rb', line 66 def start Smplkit.debug("websocket", "starting shared WebSocket (Ruby SDK initial release: in-memory only)") # Live wiring is deferred. Behave as if the handshake succeeded so the # rest of the runtime can proceed - listeners still fire for any events # other code dispatches into this instance. mark_connected! end |
#stop ⇒ Object
74 75 76 77 |
# File 'lib/smplkit/ws.rb', line 74 def stop @closed = true @connection_status = "disconnected" end |