Class: SurrealDB::Connections::WebSocket

Inherits:
Base
  • Object
show all
Defined in:
lib/surrealdb/connections/websocket.rb

Overview

WebSocket transport for SurrealDB RPC.

Uses websocket-driver for protocol handling and a background reader thread to route responses by request ID. Supports live query notifications.

Thread Safety

A single WebSocket connection is NOT safe for concurrent use from multiple threads without external synchronization. Frame writes are serialized via an internal write mutex to prevent corruption, but the request/response lifecycle (encode -> send -> wait -> decode) is not atomic. If you need concurrent access, use a separate Client per thread or wrap calls in your own Mutex.

Fiber Scheduler Compatibility

Response waiting uses ConditionVariable#wait which is compatible with Ruby's Fiber scheduler (Ruby 3.1+). This means the SDK works transparently with the async gem and similar frameworks.

Defined Under Namespace

Classes: SocketWrapper

Instance Attribute Summary collapse

Attributes inherited from Base

#rpc, #url

Instance Method Summary collapse

Methods inherited from Base

#connected?

Constructor Details

#initialize(url, **options) ⇒ WebSocket

Returns a new instance of WebSocket.



32
33
34
35
36
37
38
39
40
41
42
# File 'lib/surrealdb/connections/websocket.rb', line 32

def initialize(url, **options)
  super
  @timeout = options.fetch(:timeout, SurrealDB.configuration.timeout)
  @pending = {}
  @live_handlers = {}
  @mutex = Mutex.new
  @write_mutex = Mutex.new
  @socket = nil
  @driver = nil
  @reader_thread = nil
end

Instance Attribute Details

#timeoutInteger (readonly)

Returns response timeout in seconds.

Returns:

  • (Integer)

    response timeout in seconds



30
31
32
# File 'lib/surrealdb/connections/websocket.rb', line 30

def timeout
  @timeout
end

Instance Method Details

#closeObject



61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/surrealdb/connections/websocket.rb', line 61

def close
  return unless @connected

  @connected = false
  @driver&.close
  shutdown_reader
  @socket&.close
  @socket = nil

  notify_pending_closed
  log(:debug, 'WebSocket connection closed')
end

#connectObject



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/surrealdb/connections/websocket.rb', line 44

def connect
  uri = URI.parse(@url)
  @socket = open_socket(uri)
  ws_url = build_ws_url(uri)

  @driver = ::WebSocket::Driver.client(SocketWrapper.new(@socket, ws_url), protocols: ['cbor'])
  setup_driver_handlers

  @driver.start

  wait_for_open

  @connected = true
  start_reader
  log(:debug, "WebSocket connected to #{@url}")
end

#on_notification(live_query_id, handler) ⇒ Object

Registers a handler for live query notifications.

Parameters:

  • live_query_id (String)
  • handler (Proc, Queue)

    receives notification hashes



97
98
99
# File 'lib/surrealdb/connections/websocket.rb', line 97

def on_notification(live_query_id, handler)
  @mutex.synchronize { @live_handlers[live_query_id] = handler }
end

#remove_notification_handler(live_query_id) ⇒ Object

Removes a live query notification handler.

Parameters:

  • live_query_id (String)


103
104
105
# File 'lib/surrealdb/connections/websocket.rb', line 103

def remove_notification_handler(live_query_id)
  @mutex.synchronize { @live_handlers.delete(live_query_id) }
end

#send_request(method, params = []) ⇒ Object

Raises:



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/surrealdb/connections/websocket.rb', line 74

def send_request(method, params = [])
  raise ConnectionError, 'not connected' unless @connected

  id, encoded = @rpc.encode_request(method, params)
  entry = { result: nil, cv: ConditionVariable.new }

  @mutex.synchronize { @pending[id] = entry }

  begin
    @write_mutex.synchronize { @driver.binary(encoded) }
    wait_for_response(entry)
  ensure
    @mutex.synchronize { @pending.delete(id) }
  end
end

#supports_live_queries?Boolean

Returns:

  • (Boolean)


90
91
92
# File 'lib/surrealdb/connections/websocket.rb', line 90

def supports_live_queries?
  true
end