Module: Net::SSH::BufferedIo
Overview
This module is used to extend sockets and other IO objects, to allow them to be buffered for both read and write. This abstraction makes it quite easy to write a select-based event loop (see Net::SSH::Connection::Session#listen_to).
The general idea is that instead of calling #read directly on an IO that has been extended with this module, you call #fill (to add pending input to the internal read buffer), and then #read_available (to read from that buffer). Likewise, you don’t call #write directly, you call #enqueue to add data to the write buffer, and then #send_pending or #wait_for_pending_sends to actually send the data across the wire.
In this way you can easily use the object as an argument to IO.select, calling #fill when it is available for read, or #send_pending when it is available for write, and then call #enqueue and #read_available during the idle times.
socket = TCPSocket.new(address, port)
socket.extend(Net::SSH::BufferedIo)
ssh.listen_to(socket)
ssh.loop do
if socket.available > 0
puts socket.read_available
socket.enqueue("response\n")
end
end
Note that this module must be used to extend an instance, and should not be included in a class. If you do want to use it via an include, then you must make sure to invoke the private #initialize_buffered_io method in your class’ #initialize method:
class Foo < IO
include Net::SSH::BufferedIo
def initialize
initialize_buffered_io
# ...
end
end
Instance Attribute Summary
Attributes included from Loggable
Class Method Summary collapse
-
.extended(object) ⇒ Object
Called when the #extend is called on an object, with this module as the argument.
Instance Method Summary collapse
-
#available ⇒ Object
Returns the number of bytes available to be read from the input buffer.
-
#enqueue(data) ⇒ Object
Enqueues data in the output buffer, to be written when #send_pending is called.
-
#fill(n = 8192) ⇒ Object
Tries to read up to
n
bytes of data from the remote end, and appends the data to the input buffer. -
#pending_write? ⇒ Boolean
Returns
true
if there is data waiting in the output buffer, andfalse
otherwise. -
#read_available(length = nil) ⇒ Object
Read up to
length
bytes from the input buffer. -
#read_buffer ⇒ Object
:nodoc:.
-
#send_pending ⇒ Object
Sends as much of the pending output as possible.
-
#wait_for_pending_sends ⇒ Object
Calls #send_pending repeatedly, if necessary, blocking until the output buffer is empty.
-
#write_buffer ⇒ Object
:nodoc:.
Methods included from Loggable
#debug, #error, #fatal, #info, #lwarn
Class Method Details
.extended(object) ⇒ Object
Called when the #extend is called on an object, with this module as the argument. It ensures that the modules instance variables are all properly initialized.
54 55 56 57 |
# File 'lib/net/ssh/buffered_io.rb', line 54 def self.extended(object) # :nodoc: # need to use __send__ because #send is overridden in Socket object.__send__(:initialize_buffered_io) end |
Instance Method Details
#available ⇒ Object
Returns the number of bytes available to be read from the input buffer. (See #read_available.)
81 82 83 |
# File 'lib/net/ssh/buffered_io.rb', line 81 def available input.available end |
#enqueue(data) ⇒ Object
Enqueues data in the output buffer, to be written when #send_pending is called. Note that the data is not sent immediately by this method!
87 88 89 |
# File 'lib/net/ssh/buffered_io.rb', line 87 def enqueue(data) output.append(data) end |
#fill(n = 8192) ⇒ Object
Tries to read up to n
bytes of data from the remote end, and appends the data to the input buffer. It returns the number of bytes read, or 0 if no data was available to be read.
62 63 64 65 66 67 68 69 70 71 |
# File 'lib/net/ssh/buffered_io.rb', line 62 def fill(n = 8192) input.consume! data = recv(n) || "" debug { "read #{data.length} bytes" } input.append(data) return data.length rescue EOFError => e @input_errors << e return 0 end |
#pending_write? ⇒ Boolean
Returns true
if there is data waiting in the output buffer, and false
otherwise.
93 94 95 |
# File 'lib/net/ssh/buffered_io.rb', line 93 def pending_write? output.length > 0 end |
#read_available(length = nil) ⇒ Object
Read up to length
bytes from the input buffer. If length
is nil, all available data is read from the buffer. (See #available.)
75 76 77 |
# File 'lib/net/ssh/buffered_io.rb', line 75 def read_available(length = nil) input.read(length || available) end |
#read_buffer ⇒ Object
:nodoc:
128 129 130 |
# File 'lib/net/ssh/buffered_io.rb', line 128 def read_buffer # :nodoc: input.to_s end |
#send_pending ⇒ Object
Sends as much of the pending output as possible. Returns true
if any data was sent, and false
otherwise.
99 100 101 102 103 104 105 106 107 108 |
# File 'lib/net/ssh/buffered_io.rb', line 99 def send_pending if output.length > 0 sent = send(output.to_s, 0) debug { "sent #{sent} bytes" } output.consume!(sent) return sent > 0 else return false end end |
#wait_for_pending_sends ⇒ Object
Calls #send_pending repeatedly, if necessary, blocking until the output buffer is empty.
112 113 114 115 116 117 118 119 120 |
# File 'lib/net/ssh/buffered_io.rb', line 112 def wait_for_pending_sends send_pending while output.length > 0 result = IO.select(nil, [self]) or next next unless result[1].any? send_pending end end |
#write_buffer ⇒ Object
:nodoc:
124 125 126 |
# File 'lib/net/ssh/buffered_io.rb', line 124 def write_buffer # :nodoc: output.to_s end |