Class: Protocol::HTTY::Stream

Inherits:
Object
  • Object
show all
Defined in:
lib/protocol/htty/stream.rb

Overview

Transport an opaque byte stream over HTTY chunks.

Constant Summary collapse

PACKET_SIZE =

Since base64 encoding adds 33% overhead, we can fit 3KB of binary data into a single HTTY chunk without exceeding the typical MTU of 4KB:

1024*3

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(input, output = input, packet_size: PACKET_SIZE) ⇒ Stream

Create a stream on top of HTTY framed input and output.



19
20
21
22
23
24
25
# File 'lib/protocol/htty/stream.rb', line 19

def initialize(input, output = input, packet_size: PACKET_SIZE)
	@framer = Framer.new(::IO::Stream(input), ::IO::Stream(output))
	@packet_size = packet_size
	@buffer = +"".b
	@local_closed = false
	@remote_closed = false
end

Instance Attribute Details

#framerObject (readonly)

Returns the value of attribute framer.



27
28
29
# File 'lib/protocol/htty/stream.rb', line 27

def framer
  @framer
end

Instance Method Details

#closeObject

Close the local write side of this stream abstraction. HTTY does not define a close packet, and closing this object does not close the underlying terminal IO.



83
84
85
86
87
88
# File 'lib/protocol/htty/stream.rb', line 83

def close
	unless @local_closed
		@local_closed = true
		@framer.flush
	end
end

#closed?Boolean

Check whether the local side of the transport is closed.

Returns:

  • (Boolean)


92
93
94
# File 'lib/protocol/htty/stream.rb', line 92

def closed?
	@local_closed
end

#flushObject

Flush any buffered output through the underlying framer.



76
77
78
# File 'lib/protocol/htty/stream.rb', line 76

def flush
	@framer.flush
end

#ioObject

Return the writable IO object used by the underlying framer.



31
32
33
# File 'lib/protocol/htty/stream.rb', line 31

def io
	@framer.output
end

#read(length = nil) ⇒ Object

Read application bytes from the HTTY transport.



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/protocol/htty/stream.rb', line 38

def read(length = nil)
	return +"".b if length == 0
	
	fill(length)
	
	return nil if @buffer.empty? && @remote_closed
	return nil if @buffer.empty?
	return nil if length && @buffer.bytesize < length && !@remote_closed
	
	if length
		return @buffer.slice!(0, length)
	else
		return @buffer.slice!(0, @buffer.bytesize)
	end
end

#readable?Boolean

Check whether the remote side may still provide more data.

Returns:

  • (Boolean)


98
99
100
# File 'lib/protocol/htty/stream.rb', line 98

def readable?
	!@remote_closed
end

#write(data) ⇒ Object

Write application bytes as one or more HTTY chunks.

Raises:

  • (IOError)


58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/protocol/htty/stream.rb', line 58

def write(data)
	raise IOError, "HTTY stream is closed for writing!" if @local_closed
	
	data = data.to_s.b
	
	until data.empty?
		chunk = data.byteslice(0, @packet_size)
		@framer.write_chunk(chunk)
		data = data.byteslice(chunk.bytesize..)
	end
	
	@framer.flush
	
	return self
end