Class: Wokku::CableClient
- Inherits:
-
Object
- Object
- Wokku::CableClient
- Defined in:
- lib/wokku/cable_client.rb
Constant Summary collapse
- SUBSCRIBE_TIMEOUT =
10
Instance Method Summary collapse
- #close ⇒ Object
-
#initialize(url:, token:) ⇒ CableClient
constructor
A new instance of CableClient.
- #on_close(&block) ⇒ Object
- #on_message(&block) ⇒ Object
-
#origin_header ⇒ Object
Origin matches the cable host so ActionCable’s same-origin check passes.
- #pump(timeout = 0.05) ⇒ Object
- #send_message(payload) ⇒ Object
- #subscribe(channel:, params: {}) ⇒ Object
-
#url ⇒ Object
WebSocket::Driver duck-types these on its socket adapter:.
- #write(data) ⇒ Object
Constructor Details
#initialize(url:, token:) ⇒ CableClient
Returns a new instance of CableClient.
13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
# File 'lib/wokku/cable_client.rb', line 13 def initialize(url:, token:) @uri = URI(url) @token = token @on_message = ->(_) {} @on_close = ->(_) {} @subscribed = false @identifier = nil @socket = open_socket @driver = WebSocket::Driver.client(self) @driver.set_header("Authorization", "Bearer #{@token}") if @token && !@token.empty? @driver.set_header("Origin", origin_header) attach_driver_callbacks @driver.start end |
Instance Method Details
#close ⇒ Object
76 77 78 79 |
# File 'lib/wokku/cable_client.rb', line 76 def close @driver.close rescue nil @socket.close rescue nil end |
#on_close(&block) ⇒ Object
50 51 52 |
# File 'lib/wokku/cable_client.rb', line 50 def on_close(&block) @on_close = block end |
#on_message(&block) ⇒ Object
46 47 48 |
# File 'lib/wokku/cable_client.rb', line 46 def (&block) @on_message = block end |
#origin_header ⇒ Object
Origin matches the cable host so ActionCable’s same-origin check passes. CSRF concerns don’t apply: the CLI authenticates via Bearer token, not a cookie-borne session, so cross-site forgery is not a vector here.
31 32 33 34 35 |
# File 'lib/wokku/cable_client.rb', line 31 def origin_header scheme = @uri.scheme == "wss" ? "https" : "http" port = (@uri.port && ![ 80, 443 ].include?(@uri.port)) ? ":#{@uri.port}" : "" "#{scheme}://#{@uri.host}#{port}" end |
#pump(timeout = 0.05) ⇒ Object
66 67 68 69 70 71 72 73 74 |
# File 'lib/wokku/cable_client.rb', line 66 def pump(timeout = 0.05) ready = IO.select([@socket], nil, nil, timeout) return unless ready @driver.parse(@socket.read_nonblock(4096)) rescue IO::WaitReadable # transient rescue EOFError @on_close.call(:eof) end |
#send_message(payload) ⇒ Object
62 63 64 |
# File 'lib/wokku/cable_client.rb', line 62 def (payload) @driver.text(JSON.dump(command: "message", identifier: @identifier, data: JSON.dump(payload))) end |
#subscribe(channel:, params: {}) ⇒ Object
54 55 56 57 58 59 60 |
# File 'lib/wokku/cable_client.rb', line 54 def subscribe(channel:, params: {}) @identifier = JSON.dump({ channel: channel, **params }) @driver.text(JSON.dump(command: "subscribe", identifier: @identifier)) deadline = Time.now + SUBSCRIBE_TIMEOUT pump_until { @subscribed || Time.now > deadline } raise "subscribe timed out" unless @subscribed end |
#url ⇒ Object
WebSocket::Driver duck-types these on its socket adapter:
38 39 40 |
# File 'lib/wokku/cable_client.rb', line 38 def url @uri.to_s end |
#write(data) ⇒ Object
42 43 44 |
# File 'lib/wokku/cable_client.rb', line 42 def write(data) @socket.write(data) end |