class Framer
Encode and decode HTTY chunks on top of byte-oriented IO objects.
Definitions
def initialize(input, output = input)
Create a framer around the given input and output streams.
Signature
-
parameter
inputInterface(:read) The stream to read framed packets from.
-
parameter
outputInterface(:write, :flush) | Nil The stream to write framed packets to.
Implementation
def initialize(input, output = input)
@input = input
@output = output
end
def write_chunk(payload)
Write a single HTTY chunk to the output stream.
Signature
-
parameter
payloadString | Array(Integer) The opaque bytes to encode.
-
returns
void
Implementation
def write_chunk(payload)
encoded = Base64.strict_encode64(payload.to_s.b)
@output.write("#{DCS}#{PREFIX}#{encoded}#{ST}")
end
def read_chunk
Read the next HTTY chunk from the input stream. Non-HTTY terminal output is ignored until a valid chunk prefix is found.
Signature
-
returns
String | Nil The decoded payload, or
nilon end of stream.-
raises
ProtocolError If the chunk prefix or chunk structure is invalid.
-
raises
ArgumentError If the packet payload is not valid base64.
-
raises
EOFError If the chunk terminator is missing.
Implementation
def read_chunk
while payload = read_payload
if payload.start_with?("HTTY;") && !payload.start_with?(PREFIX)
raise ProtocolError, "Unsupported HTTY chunk version: #{payload.inspect}"
end
next unless payload.start_with?(PREFIX)
encoded = payload.delete_prefix(PREFIX)
return Base64.strict_decode64(encoded)
end
return nil
end
def flush
Flush the output stream if it supports flushing.
Signature
-
returns
void
Implementation
def flush
@output.flush if @output.respond_to?(:flush)
end
def close
Close the wrapped input and output streams. If input and output are the same object, it is only closed once.
Signature
-
returns
void
Implementation
def close
@output.close if @output.respond_to?(:close)
@input.close if !@input.equal?(@output) && @input.respond_to?(:close)
end
def closed?
Check whether the output stream has been closed.
Signature
-
returns
bool True if the output stream reports that it is closed.
Implementation
def closed?
@output.respond_to?(:closed?) && @output.closed?
end