module Clacky::Channel::Adapters::Feishu::WSClient::ProtoFrame
def self.decode(buf)
def self.decode(buf) buf = buf.b pos = 0 result = { headers: {}, payload: "".b } while pos < buf.bytesize tag_byte, pos = read_varint(buf, pos) field_number = tag_byte >> 3 wire_type = tag_byte & 0x7 case wire_type when 0 # varint val, pos = read_varint(buf, pos) case field_number when 1 then result[:seq_id] = val when 2 then result[:log_id] = val when 3 then result[:service] = val when 4 then result[:method] = val end when 2 # length-delimited len, pos = read_varint(buf, pos) bytes = buf.byteslice(pos, len) pos += len case field_number when 5 # header entry k, v = decode_header(bytes) result[:headers][k] = v if k when 7 then result[:payload_type] = bytes.force_encoding("UTF-8") when 8 then result[:payload] = bytes end else break # unknown wire type, stop parsing end end result end
def self.decode_header(buf)
def self.decode_header(buf) buf = buf.b pos = 0 key = nil val = nil while pos < buf.bytesize tag_byte, pos = read_varint(buf, pos) field_number = tag_byte >> 3 wire_type = tag_byte & 0x7 if wire_type == 2 len, pos = read_varint(buf, pos) bytes = buf.byteslice(pos, len) pos += len case field_number when 1 then key = bytes.force_encoding("UTF-8") when 2 then val = bytes.force_encoding("UTF-8") end else break end end [key, val] end
def self.encode(frame)
def self.encode(frame) buf = "".b buf << encode_varint(1, frame[:seq_id] || 0) buf << encode_varint(2, frame[:log_id] || 0) buf << encode_varint(3, frame[:service] || 0) buf << encode_varint(4, frame[:method] || 0) (frame[:headers] || {}).each do |k, v| header_bytes = encode_string(1, k.to_s) + encode_string(2, v.to_s) buf << encode_length_delimited(5, header_bytes) end if frame[:payload] payload_bytes = frame[:payload].respond_to?(:b) ? frame[:payload].b : frame[:payload].to_s.b buf << encode_length_delimited(8, payload_bytes) end buf end
def self.encode_length_delimited(field_number, bytes)
def self.encode_length_delimited(field_number, bytes) tag = (field_number << 3) | 2 # wire type 2 encode_raw_varint(tag) + encode_raw_varint(bytes.bytesize) + bytes end
def self.encode_raw_varint(value)
def self.encode_raw_varint(value) bytes = "".b loop do byte = value & 0x7F value >>= 7 byte |= 0x80 if value > 0 bytes << byte break if value == 0 end bytes end
def self.encode_string(field_number, str)
def self.encode_string(field_number, str) bytes = str.encode("UTF-8").b encode_length_delimited(field_number, bytes) end
def self.encode_varint(field_number, value)
def self.encode_varint(field_number, value) tag = (field_number << 3) | 0 # wire type 0 encode_raw_varint(tag) + encode_raw_varint(value) end
def self.read_varint(buf, pos)
def self.read_varint(buf, pos) result = 0 shift = 0 loop do byte = buf.getbyte(pos) raise "unexpected end of buffer at pos #{pos}" if byte.nil? pos += 1 result |= (byte & 0x7F) << shift break unless byte & 0x80 != 0 shift += 7 end [result, pos] end