Class: Supabase::Realtime::Sockets::WebsocketClientSimple

Inherits:
Object
  • Object
show all
Includes:
Supabase::Realtime::Socket
Defined in:
lib/supabase/realtime/sockets/websocket_client_simple.rb

Overview

Supabase::Realtime::Socket implementation backed by the websocket-client-simple gem.

The underlying gem spawns a background thread to read frames from the server, so every callback this adapter fires (on_open / on_message / on_close / on_error — and downstream, every user listener registered on a Channel) runs on **that background thread**. Callers are responsible for thread-safety in their listeners.

require "supabase/realtime"
require "supabase/realtime/sockets/websocket_client_simple"

socket = Supabase::Realtime::Sockets::WebsocketClientSimple.new(url: ws_url)
client = Supabase::Realtime::Client.new(url: ws_url, socket: socket)
client.connect

Instance Method Summary collapse

Methods included from Supabase::Realtime::Socket

#close_callbacks, #error_callbacks, #message_callbacks, #on_close, #on_error, #on_message, #on_open, #open_callbacks

Constructor Details

#initialize(url:, headers: {}, connector: ::WebSocket::Client::Simple) ⇒ WebsocketClientSimple

Returns a new instance of WebsocketClientSimple.

Parameters:

  • url (String)

    full ws(s):// URL including query params

  • headers (Hash) (defaults to: {})

    extra HTTP headers sent on the upgrade request

  • connector (#connect) (defaults to: ::WebSocket::Client::Simple)

    dependency injection seam — defaults to ::WebSocket::Client::Simple. Tests pass a fake that returns a stub WS client so we never open a real socket.



32
33
34
35
36
37
# File 'lib/supabase/realtime/sockets/websocket_client_simple.rb', line 32

def initialize(url:, headers: {}, connector: ::WebSocket::Client::Simple)
  @url       = url
  @headers   = headers
  @connector = connector
  @ws        = nil
end

Instance Method Details

#closeObject



52
53
54
55
# File 'lib/supabase/realtime/sockets/websocket_client_simple.rb', line 52

def close
  @ws&.close
  @ws = nil
end

#connectObject



39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/supabase/realtime/sockets/websocket_client_simple.rb', line 39

def connect
  return if connected?

  self_ref = self
  @ws = @connector.connect(@url, headers: @headers) do |client|
    client.on(:open)    { self_ref.fire_open }
    client.on(:message) { |msg| self_ref.fire_message(msg) }
    client.on(:close)   { |reason| self_ref.fire_close(reason) }
    client.on(:error)   { |err| self_ref.fire_error(err) }
  end
  nil
end

#connected?Boolean

Returns:

  • (Boolean)


61
62
63
# File 'lib/supabase/realtime/sockets/websocket_client_simple.rb', line 61

def connected?
  !@ws.nil? && @ws.open?
end

#fire_close(_reason = nil) ⇒ Object



83
84
85
86
# File 'lib/supabase/realtime/sockets/websocket_client_simple.rb', line 83

def fire_close(_reason = nil)
  @ws = nil
  close_callbacks.each(&:call)
end

#fire_error(err) ⇒ Object



88
89
90
# File 'lib/supabase/realtime/sockets/websocket_client_simple.rb', line 88

def fire_error(err)
  error_callbacks.each { |cb| cb.call(err) }
end

#fire_message(msg) ⇒ Object

websocket-client-simple yields a Frame::Incoming object whose #data holds the payload and whose #type is :text / :binary / :ping / etc. We only forward text frames — Phoenix doesn’t use binary.



76
77
78
79
80
81
# File 'lib/supabase/realtime/sockets/websocket_client_simple.rb', line 76

def fire_message(msg)
  return unless msg.respond_to?(:type) ? msg.type == :text : true

  payload = msg.respond_to?(:data) ? msg.data : msg.to_s
  message_callbacks.each { |cb| cb.call(payload) }
end

#fire_openObject

—– Internal callback shims (called by the WS background thread) —– Public so the connect block can reach them, not part of the Socket contract callers should use.



69
70
71
# File 'lib/supabase/realtime/sockets/websocket_client_simple.rb', line 69

def fire_open
  open_callbacks.each(&:call)
end

#send(payload) ⇒ Object



57
58
59
# File 'lib/supabase/realtime/sockets/websocket_client_simple.rb', line 57

def send(payload)
  @ws&.send(payload)
end