Class: Tep::WebSocket::Driver

Inherits:
Object
  • Object
show all
Defined in:
lib/tep/websocket/driver.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(fd) ⇒ Driver

Returns a new instance of Driver.



34
35
36
37
38
39
40
41
42
43
44
# File 'lib/tep/websocket/driver.rb', line 34

def initialize(fd)
  @fd             = fd
  @max_frame_size = Tep::WebSocket::DEFAULT_MAX_FRAME
  @subprotocol    = ""
  @h_open    = Tep::WebSocket::Handler.new
  @h_message = Tep::WebSocket::Handler.new
  @h_close   = Tep::WebSocket::Handler.new
  @h_ping    = Tep::WebSocket::Handler.new
  @h_pong    = Tep::WebSocket::Handler.new
  @h_error   = Tep::WebSocket::Handler.new
end

Instance Attribute Details

#fdObject

Returns the value of attribute fd.



27
28
29
# File 'lib/tep/websocket/driver.rb', line 27

def fd
  @fd
end

#h_closeObject

Callback slots. Each holds a subclass of Tep::WebSocket::Handler (or the base) that gets ‘handle_event(event)` called when the corresponding wire event arrives. Defaults to a no-op base so the slot is type-safe pre-set.



32
33
34
# File 'lib/tep/websocket/driver.rb', line 32

def h_close
  @h_close
end

#h_errorObject

Callback slots. Each holds a subclass of Tep::WebSocket::Handler (or the base) that gets ‘handle_event(event)` called when the corresponding wire event arrives. Defaults to a no-op base so the slot is type-safe pre-set.



32
33
34
# File 'lib/tep/websocket/driver.rb', line 32

def h_error
  @h_error
end

#h_messageObject

Callback slots. Each holds a subclass of Tep::WebSocket::Handler (or the base) that gets ‘handle_event(event)` called when the corresponding wire event arrives. Defaults to a no-op base so the slot is type-safe pre-set.



32
33
34
# File 'lib/tep/websocket/driver.rb', line 32

def h_message
  @h_message
end

#h_openObject

Callback slots. Each holds a subclass of Tep::WebSocket::Handler (or the base) that gets ‘handle_event(event)` called when the corresponding wire event arrives. Defaults to a no-op base so the slot is type-safe pre-set.



32
33
34
# File 'lib/tep/websocket/driver.rb', line 32

def h_open
  @h_open
end

#h_pingObject

Callback slots. Each holds a subclass of Tep::WebSocket::Handler (or the base) that gets ‘handle_event(event)` called when the corresponding wire event arrives. Defaults to a no-op base so the slot is type-safe pre-set.



32
33
34
# File 'lib/tep/websocket/driver.rb', line 32

def h_ping
  @h_ping
end

#h_pongObject

Callback slots. Each holds a subclass of Tep::WebSocket::Handler (or the base) that gets ‘handle_event(event)` called when the corresponding wire event arrives. Defaults to a no-op base so the slot is type-safe pre-set.



32
33
34
# File 'lib/tep/websocket/driver.rb', line 32

def h_pong
  @h_pong
end

#max_frame_sizeObject

Returns the value of attribute max_frame_size.



27
28
29
# File 'lib/tep/websocket/driver.rb', line 27

def max_frame_size
  @max_frame_size
end

#subprotocolObject

Returns the value of attribute subprotocol.



27
28
29
# File 'lib/tep/websocket/driver.rb', line 27

def subprotocol
  @subprotocol
end

Class Method Details

.encode_close_payload(code, reason) ⇒ Object

Close payload: 2-byte big-endian code + UTF-8 reason. Per §5.5.1 the payload may be omitted (close with no body); if ‘code == 0` we emit an empty payload.



117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/tep/websocket/driver.rb', line 117

def self.encode_close_payload(code, reason)
  if code == 0
    return ""
  end
  out = Tep::WebSocket::Frame.byte_to_chr((code >> 8) & 0xff) +
        Tep::WebSocket::Frame.byte_to_chr(code & 0xff)
  if reason.length > 123
    out + reason[0, 123]
  else
    out + reason
  end
end

.send_frame(fd, opcode, payload) ⇒ Object

Build the frame bytes (unmasked, server-side) and write via sphttp_write_bytes (binary-safe, explicit length).



108
109
110
111
112
# File 'lib/tep/websocket/driver.rb', line 108

def self.send_frame(fd, opcode, payload)
  frame = Tep::WebSocket::Frame.new(true, opcode, payload)
  bytes = frame.encode_unmasked
  Sock.sphttp_write_bytes(fd, bytes, bytes.length)
end

Instance Method Details

#binary(bytes) ⇒ Object

Send a binary frame.



84
85
86
# File 'lib/tep/websocket/driver.rb', line 84

def binary(bytes)
  Driver.send_frame(@fd, Tep::WebSocket::OPCODE_BINARY, bytes)
end

#close(code, reason) ⇒ Object

Send a close frame with code + reason. Reason capped at 123 bytes so the 2-byte code + reason fits in a control frame’s 125-byte payload limit.



101
102
103
104
# File 'lib/tep/websocket/driver.rb', line 101

def close(code, reason)
  body = Driver.encode_close_payload(code, reason)
  Driver.send_frame(@fd, Tep::WebSocket::OPCODE_CLOSE, body)
end

#ping(payload) ⇒ Object

Send a ping with optional payload (<=125 bytes).



89
90
91
# File 'lib/tep/websocket/driver.rb', line 89

def ping(payload)
  Driver.send_frame(@fd, Tep::WebSocket::OPCODE_PING, payload)
end

#pong(payload) ⇒ Object

Send a pong with the matching ping’s payload (per §5.5.3).



94
95
96
# File 'lib/tep/websocket/driver.rb', line 94

def pong(payload)
  Driver.send_frame(@fd, Tep::WebSocket::OPCODE_PONG, payload)
end

#set_fd(new_fd) ⇒ Object

Reassign the underlying fd. Used by the server-side upgrade path: the user handler builds the Driver with a placeholder fd (since the client fd isn’t visible at handler-dispatch time), and the write_response branch sets the real fd here right before constructing the Connection.



55
56
57
# File 'lib/tep/websocket/driver.rb', line 55

def set_fd(new_fd)
  @fd = new_fd
end

#set_max_frame_size(n) ⇒ Object



46
47
48
# File 'lib/tep/websocket/driver.rb', line 46

def set_max_frame_size(n)
  @max_frame_size = n
end

#set_on_close(h) ⇒ Object



65
# File 'lib/tep/websocket/driver.rb', line 65

def set_on_close(h);   @h_close = h;   end

#set_on_error(h) ⇒ Object



68
# File 'lib/tep/websocket/driver.rb', line 68

def set_on_error(h);   @h_error = h;   end

#set_on_message(h) ⇒ Object



64
# File 'lib/tep/websocket/driver.rb', line 64

def set_on_message(h); @h_message = h; end

#set_on_open(h) ⇒ Object



63
# File 'lib/tep/websocket/driver.rb', line 63

def set_on_open(h);    @h_open = h;    end

#set_on_ping(h) ⇒ Object



66
# File 'lib/tep/websocket/driver.rb', line 66

def set_on_ping(h);    @h_ping = h;    end

#set_on_pong(h) ⇒ Object



67
# File 'lib/tep/websocket/driver.rb', line 67

def set_on_pong(h);    @h_pong = h;    end

#set_subprotocol(name) ⇒ Object



59
60
61
# File 'lib/tep/websocket/driver.rb', line 59

def set_subprotocol(name)
  @subprotocol = name
end

#text(s) ⇒ Object

Send a text frame.



71
72
73
# File 'lib/tep/websocket/driver.rb', line 71

def text(s)
  Driver.send_frame(@fd, Tep::WebSocket::OPCODE_TEXT, s)
end

#write(s) ⇒ Object

Streamer-shape alias for ‘text` so a Driver can stand in anywhere `Tep::Streamer`-style code calls `out.write(s)`. Used by Tep::Llm.chat_stream to write LLM deltas as WS frames (one frame per SSE-shaped chunk).



79
80
81
# File 'lib/tep/websocket/driver.rb', line 79

def write(s)
  Driver.send_frame(@fd, Tep::WebSocket::OPCODE_TEXT, s)
end