Protocol::HTTYSourceProtocolHTTYFramer

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 input Interface(:read)

The stream to read framed packets from.

parameter output Interface(: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 payload String | 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 nil on 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