Module: Terminalwire::V2::Codec

Defined in:
lib/terminalwire/v2/codec.rb

Overview

Pure bytes <-> frame conversion. A frame is a Hash with string keys (the wire shape). No I/O, no transport — this is the sans-IO seam the conformance corpus exercises directly.

Constant Summary collapse

MAX_SID =

Largest valid stream id: a signed 64-bit max. Go decodes sids into int64, so anything above this would wrap to a negative (colliding) sid there; bounding it here keeps all three impls' sid validity identical.

(1 << 63) - 1

Class Method Summary collapse

Class Method Details

.decode(bytes) ⇒ Hash

Returns the decoded frame with string keys.

Parameters:

  • bytes (String)

    MessagePack bytes for exactly one frame

Returns:

  • (Hash)

    the decoded frame with string keys

Raises:



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/terminalwire/v2/codec.rb', line 28

def decode(bytes)
  obj =
    begin
      MessagePack.unpack(bytes)
    rescue StandardError => e
      raise ProtocolError, "malformed msgpack: #{e.message}"
    end

  raise ProtocolError, "frame must be a map" unless obj.is_a?(Hash)
  # 't' must be a NON-EMPTY type string. Go and Elixir reject "" at the codec;
  # Ruby used to let it through to the state machine. An empty type is not a
  # valid frame — reject it here so all three behave identically.
  raise ProtocolError, "frame missing string 't'" unless obj["t"].is_a?(String) && !obj["t"].empty?
  # 'sid' must be a non-negative integer that fits in a signed 64-bit int (see
  # MAX_SID): real sids are small and server-allocated, and the range bound keeps
  # the three impls aligned (Go would otherwise wrap a uint64 sid to a negative).
  sid = obj["sid"]
  unless sid.is_a?(Integer) && sid >= 0 && sid <= MAX_SID
    raise ProtocolError, "frame missing integer 'sid'"
  end

  obj
end

.encode(frame) ⇒ String

Returns MessagePack bytes (binary encoding).

Parameters:

  • frame (Hash)

    a frame with string keys

Returns:

  • (String)

    MessagePack bytes (binary encoding)

Raises:



19
20
21
22
23
# File 'lib/terminalwire/v2/codec.rb', line 19

def encode(frame)
  raise ProtocolError, "frame must be a Hash, got #{frame.class}" unless frame.is_a?(Hash)

  MessagePack.pack(frame)
end