Class: Antigravity::Protocol
- Inherits:
-
Object
- Object
- Antigravity::Protocol
- Defined in:
- lib/antigravity/protocol.rb
Overview
Hand-rolled protobuf encoding/decoding for the 2 stdio handshake messages:
InputConfig (SDK → localharness via stdin)
OutputConfig (localharness → SDK via stdout)
Uses raw protobuf wire format to avoid the google-protobuf gem dependency. See: https://github.com/palladius/antigravity-ruby-sdk/issues/7
Wire format reference: https://protobuf.dev/programming-guides/encoding/ Varint: wire type 0, tag = (field_number << 3) | 0 Length-delimited: wire type 2, tag = (field_number << 3) | 2
Class Method Summary collapse
-
.decode_output_config(data) ⇒ Object
--- Decoding: OutputConfig --- message OutputConfig { int32 port = 1; string api_key = 2; }.
-
.encode_input_config(storage_directory:, bind_address: 'localhost', env: {}) ⇒ Object
--- Encoding: InputConfig --- message InputConfig { string storage_directory = 1; uint32 port = 2; # optional, we leave 0 string bind_address = 3; # default "localhost" ClientInfo client_info = 4; map<string, string> env = 5; } message ClientInfo { string language = 1; string version = 2; string language_version = 3; string os = 4; string os_version = 5; }.
-
.read_length_prefixed(io, timeout: 10) ⇒ Object
Read a length-prefixed frame from an IO (blocking).
Class Method Details
.decode_output_config(data) ⇒ Object
--- Decoding: OutputConfig --- message OutputConfig { int32 port = 1; string api_key = 2; }
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/antigravity/protocol.rb', line 60 def self.decode_output_config(data) raise ProtocolError, 'Data too short for length prefix' if data.bytesize < 4 declared_len = data[0..3].unpack1('V') payload = data[4..] raise ProtocolError, "Truncated payload: expected #{declared_len}, got #{payload&.bytesize || 0}" if payload.nil? || payload.bytesize < declared_len result = { port: 0, api_key: '' } pos = 0 while pos < declared_len tag_byte, new_pos = decode_varint(payload, pos) pos = new_pos field_number = tag_byte >> 3 wire_type = tag_byte & 0x07 case wire_type when 0 # varint value, pos = decode_varint(payload, pos) result[:port] = value if field_number == 1 when 2 # length-delimited length, pos = decode_varint(payload, pos) value = payload[pos, length] pos += length result[:api_key] = value.force_encoding('UTF-8') if field_number == 2 else raise ProtocolError, "Unsupported wire type #{wire_type} at position #{pos}" end end result end |
.encode_input_config(storage_directory:, bind_address: 'localhost', env: {}) ⇒ Object
--- Encoding: InputConfig --- message InputConfig { string storage_directory = 1; uint32 port = 2; # optional, we leave 0 string bind_address = 3; # default "localhost" ClientInfo client_info = 4; map<string, string> env = 5; } message ClientInfo { string language = 1; string version = 2; string language_version = 3; string os = 4; string os_version = 5; }
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/antigravity/protocol.rb', line 32 def self.encode_input_config(storage_directory:, bind_address: 'localhost', env: {}) buf = ''.b # field 1: storage_directory (string) buf << encode_string_field(1, storage_directory) # field 3: bind_address (string, default "localhost") buf << encode_string_field(3, bind_address) # field 4: client_info (embedded message) client_info = encode_client_info buf << encode_bytes_field(4, client_info) # field 5: env map entries (each is an embedded message with key=1, value=2) env.each do |key, value| entry = encode_string_field(1, key.to_s) + encode_string_field(2, value.to_s) buf << encode_bytes_field(5, entry) end # Length-prefix: 4-byte little-endian uint32 [buf.bytesize].pack('V') + buf end |
.read_length_prefixed(io, timeout: 10) ⇒ Object
Read a length-prefixed frame from an IO (blocking). Returns the raw payload bytes.
96 97 98 99 100 101 102 103 104 105 |
# File 'lib/antigravity/protocol.rb', line 96 def self.read_length_prefixed(io, timeout: 10) len_bytes = read_exactly(io, 4, timeout: timeout) raise ProtocolError, 'EOF reading length prefix' unless len_bytes&.bytesize == 4 payload_len = len_bytes.unpack1('V') raise ProtocolError, "Unreasonable payload length: #{payload_len}" if payload_len > 1_000_000 frame = [payload_len].pack('V') + read_exactly(io, payload_len, timeout: timeout) frame end |