Class: Vizcore::Server::WebSocketHandler

Inherits:
Object
  • Object
show all
Defined in:
lib/vizcore/server/websocket_handler.rb

Overview

Stateless WebSocket endpoint manager for frame broadcast transport.

Constant Summary collapse

PROTOCOL_VERSION =
"vizcore.frame.v1"
MAX_BUFFERED_FRAME_BYTES =
1_000_000
DROPPABLE_MESSAGE_TYPES =
Set["audio_frame"].freeze
VALID_CLIENT_ROLES =
Set["projector", "control", "monitor"].freeze
CONTROL_ROLE =
"control".freeze
PROJECTOR_ROLE =
"projector".freeze
MONITOR_ROLE =
"monitor".freeze
READ_ONLY_ROLES =
Set[PROJECTOR_ROLE, MONITOR_ROLE].freeze
READ_ONLY_ALLOWED_MESSAGE_TYPES =
Set["latency_probe", "client_runtime_error"].freeze
LOW_BANDWIDTH_ROLES =
Set[CONTROL_ROLE, MONITOR_ROLE].freeze
CONTROL_AUDIO_FRAME_INTERVAL =
4

Class Method Summary collapse

Class Method Details

.backpressure_statusHash

Returns current websocket backpressure metrics for control/status surfaces.

Returns:

  • (Hash)

    current websocket backpressure metrics for control/status surfaces.



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/vizcore/server/websocket_handler.rb', line 91

def backpressure_status
  mutex.synchronize do
    clients = sockets.map { |socket| backpressure_client_status(socket) }
    {
      threshold_bytes: MAX_BUFFERED_FRAME_BYTES,
      active_clients: sockets.size,
      total: {
        dropped_frames: socket_backpressure_totals[:dropped_frames],
        dropped_payload_bytes: socket_backpressure_totals[:dropped_payload_bytes],
        sent_frames: socket_backpressure_totals[:sent_frames],
        sent_payload_bytes: socket_backpressure_totals[:sent_payload_bytes],
        avg_payload_bytes: average(
          socket_backpressure_totals[:sent_payload_bytes],
          socket_backpressure_totals[:sent_frames]
        )
      },
      clients: clients
    }
  end
end

.broadcast(type:, payload:) ⇒ Boolean

Broadcast one typed payload to all active websocket clients.

Parameters:

  • type (String)
  • payload (Hash)

Returns:

  • (Boolean)

    false when websocket backend is unavailable



49
50
51
52
53
54
55
56
57
58
59
# File 'lib/vizcore/server/websocket_handler.rb', line 49

def broadcast(type:, payload:)
  return false unless faye_websocket_class

  message = JSON.generate(protocol: PROTOCOL_VERSION, type: type, payload: payload)

  each_socket do |socket|
    send_message(socket, message, type: type)
  end

  true
end

.call(env) ⇒ Array

Rack endpoint for WebSocket upgrade handling.

Parameters:

  • env (Hash)

Returns:

  • (Array)


30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/vizcore/server/websocket_handler.rb', line 30

def call(env)
  websocket_klass = faye_websocket_class
  return dependency_error_response unless websocket_klass
  return [426, text_headers, ["WebSocket upgrade required"]] unless websocket_klass.websocket?(env)

  socket = websocket_klass.new(env, nil, ping: 15)

  socket.on(:open) { register(socket, role: websocket_role_for_env(env)) }
  socket.on(:close) { unregister(socket) }
  socket.on(:message) { |event| handle_message(socket, event.data) }

  socket.rack_response
end

.clear_message_handlervoid

This method returns an undefined value.

Clear inbound message handler.



123
124
125
# File 'lib/vizcore/server/websocket_handler.rb', line 123

def clear_message_handler
  mutex.synchronize { @message_handler = nil }
end

.connection_countInteger

Returns:

  • (Integer)


76
77
78
# File 'lib/vizcore/server/websocket_handler.rb', line 76

def connection_count
  mutex.synchronize { sockets.size }
end

.dropped_frame_countInteger

Returns:

  • (Integer)


86
87
88
# File 'lib/vizcore/server/websocket_handler.rb', line 86

def dropped_frame_count
  mutex.synchronize { @dropped_frame_count || 0 }
end

.last_errorStandardError?

Returns:

  • (StandardError, nil)


81
82
83
# File 'lib/vizcore/server/websocket_handler.rb', line 81

def last_error
  mutex.synchronize { @last_error }
end

.on_message {|message| ... } ⇒ void

This method returns an undefined value.

Register one inbound message handler for client -> server control messages.

Yield Parameters:

  • message (Hash)


116
117
118
# File 'lib/vizcore/server/websocket_handler.rb', line 116

def on_message(&block)
  mutex.synchronize { @message_handler = block }
end

.send_to(socket, type:, payload:) ⇒ Boolean

Send one typed payload to a single websocket client.

Parameters:

  • socket (#send)
  • type (String)
  • payload (Hash)

Returns:

  • (Boolean)

    false when websocket backend is unavailable



67
68
69
70
71
72
73
# File 'lib/vizcore/server/websocket_handler.rb', line 67

def send_to(socket, type:, payload:)
  return false unless faye_websocket_class

  message = JSON.generate(protocol: PROTOCOL_VERSION, type: type, payload: payload)
  send_message(socket, message, type: type)
  true
end