Module: Muxr::Protocol
- Defined in:
- lib/muxr/protocol.rb
Overview
Length-prefixed framing for client <-> server messages over a Unix socket.
Wire format per message:
[1 byte type][4 bytes BE length][length bytes payload]
Types are single ASCII letters so they’re easy to recognise in tcpdump or hex dumps:
H hello (client -> server, payload: "ROWS COLS")
I input (client -> server, payload: raw STDIN bytes)
R resize (client -> server, payload: "ROWS COLS")
B bye (either way, payload: optional reason string)
O output (server -> client, payload: raw bytes to write to STDOUT)
Constant Summary collapse
- HELLO =
"H".freeze
- INPUT =
"I".freeze
- RESIZE =
"R".freeze
- BYE =
"B".freeze
- OUTPUT =
"O".freeze
- HEADER_SIZE =
5
Class Method Summary collapse
-
.decode_size(payload) ⇒ Object
Returns [rows, cols] or nil if malformed.
-
.encode_size(rows, cols) ⇒ Object
Encodes a “ROWS COLS” string for HELLO / RESIZE payloads.
-
.read(io) ⇒ Object
Reads exactly one framed message from
io. -
.write(io, type, payload = "") ⇒ Object
Writes one framed message.
Class Method Details
.decode_size(payload) ⇒ Object
Returns [rows, cols] or nil if malformed.
53 54 55 56 57 58 59 60 |
# File 'lib/muxr/protocol.rb', line 53 def self.decode_size(payload) parts = payload.to_s.strip.split(/\s+/) return nil unless parts.length == 2 r = Integer(parts[0]) rescue nil c = Integer(parts[1]) rescue nil return nil unless r && c [r, c] end |
.encode_size(rows, cols) ⇒ Object
Encodes a “ROWS COLS” string for HELLO / RESIZE payloads.
48 49 50 |
# File 'lib/muxr/protocol.rb', line 48 def self.encode_size(rows, cols) "#{rows.to_i} #{cols.to_i}" end |
.read(io) ⇒ Object
Reads exactly one framed message from io. Returns [type, payload] or nil on EOF / truncated frame. Blocks until the full message arrives.
25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
# File 'lib/muxr/protocol.rb', line 25 def self.read(io) header = read_exact(io, HEADER_SIZE) return nil unless header type = header[0] length = header.byteslice(1, 4).unpack1("N") payload = if length.zero? "" else read_exact(io, length) end return nil unless payload [type, payload] end |
.write(io, type, payload = "") ⇒ Object
Writes one framed message. payload is treated as raw bytes (binary).
41 42 43 44 45 |
# File 'lib/muxr/protocol.rb', line 41 def self.write(io, type, payload = "") raise ArgumentError, "type must be a single byte" unless type.is_a?(String) && type.bytesize == 1 bytes = payload.to_s.b io.write(type + [bytes.bytesize].pack("N") + bytes) end |