Module: EventMachine::Ssh::Connection::Channel::Interactive
- Includes:
- EventMachine::Ssh::Callbacks
- Defined in:
- lib/em-ssh/connection/channel/interactive.rb
Overview
This module adds functionality to any channel it extends. It mainly provides functionality to help interactive behaviour on said channel.
-
#send_data (improved) that can append ‘line terminators’.
-
#wait_for - waits for the shell to send data containing the given string.
-
#send_and_wait - sends a string and waits for a response containing a specified pattern.
-
#expect - waits for a number of seconds until a pattern is matched by the channel output.
Constant Summary collapse
- DEFAULT_TIMEOUT =
15
Instance Attribute Summary collapse
-
#line_terminator ⇒ Object
@return a string (rn) to append to every command.
Class Method Summary collapse
Instance Method Summary collapse
-
#clear_buffer! ⇒ Object
Remove any data currently in the buffer.
-
#dump_buffer ⇒ Object
(also: #dump_buffers)
@returns Returns a #to_s object describing the dump of the content of the buffers used by the methods of the interactive module mixed in the host object.
-
#expect(strregex, send_str = nil, opts = {}) ⇒ Shell, String
Wait for a number of seconds until a specified string or regexp is matched by the data returned from the ssh channel.
-
#init_interactive_module ⇒ Object
When this module extends an object this method is automatically called (via self#extended).
-
#send_and_wait(send_str, wait_str = nil, opts = {}) ⇒ String
Send a string to the server and wait for a response containing a specified String or Regex.
-
#send_data(d, send_newline = false) ⇒ Object
Send data to the ssh server shell.
-
#wait_for(strregex, opts = { }) ⇒ String
Wait for the shell to send data containing the given string.
Methods included from EventMachine::Ssh::Callbacks
#callbacks, #callbacks=, #fire, #on, #on_next
Instance Attribute Details
#line_terminator ⇒ Object
@return a string (rn) to append to every command
29 30 31 |
# File 'lib/em-ssh/connection/channel/interactive.rb', line 29 def line_terminator @line_terminator end |
Class Method Details
.extended(channel) ⇒ Object
31 32 33 |
# File 'lib/em-ssh/connection/channel/interactive.rb', line 31 def self.extended(channel) channel.init_interactive_module end |
Instance Method Details
#clear_buffer! ⇒ Object
Remove any data currently in the buffer.
55 56 57 |
# File 'lib/em-ssh/connection/channel/interactive.rb', line 55 def clear_buffer! @buffer = '' end |
#dump_buffer ⇒ Object Also known as: dump_buffers
@returns Returns a #to_s object describing the dump of the content of the buffers used by
the methods of the interactive module mixed in the host object.
48 49 50 |
# File 'lib/em-ssh/connection/channel/interactive.rb', line 48 def dump_buffer @buffer.dump end |
#expect(strregex, send_str = nil, opts = {}) ⇒ Shell, String
Wait for a number of seconds until a specified string or regexp is matched by the data returned from the ssh channel. Optionally send a given string first.
If a block is not provided the current Fiber will yield until strregex matches or :timeout is reached.
If a block is provided expect will return.
81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/em-ssh/connection/channel/interactive.rb', line 81 def expect(strregex, send_str = nil, opts = {}) send_str, opts = nil, send_str if send_str.is_a?(Hash) if block_given? Fiber.new { yield send_str ? send_and_wait(send_str, strregex, opts) : wait_for(strregex, opts) }.resume self else send_str ? send_and_wait(send_str, strregex, opts) : wait_for(strregex, opts) end end |
#init_interactive_module ⇒ Object
When this module extends an object this method is automatically called (via self#extended). In other cases (include, prepend?), you need to call this method manually before use of the channel.
37 38 39 40 41 42 43 44 |
# File 'lib/em-ssh/connection/channel/interactive.rb', line 37 def init_interactive_module @buffer = '' @line_terminator = "\n" on_data do |ch, data| @buffer += data fire(:data, data) end end |
#send_and_wait(send_str, wait_str = nil, opts = {}) ⇒ String
Send a string to the server and wait for a response containing a specified String or Regex.
96 97 98 99 |
# File 'lib/em-ssh/connection/channel/interactive.rb', line 96 def send_and_wait(send_str, wait_str = nil, opts = {}) send_data(send_str, true) return wait_for(wait_str, opts) end |
#send_data(d, send_newline = false) ⇒ Object
Send data to the ssh server shell. You generally don’t need to call this.
106 107 108 109 110 111 112 |
# File 'lib/em-ssh/connection/channel/interactive.rb', line 106 def send_data(d, send_newline=false) if send_newline super("#{d}#{@line_terminator}") else super("#{d}") end end |
#wait_for(strregex, opts = { }) ⇒ String
Wait for the shell to send data containing the given string.
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
# File 'lib/em-ssh/connection/channel/interactive.rb', line 122 def wait_for(strregex, opts = { }) ### log = opts[:log] || NullLogger.new timeout_value = opts[:timeout].is_a?(Fixnum) ? opts[:timeout] : DEFAULT_TIMEOUT ### log.debug("wait_for(#{strregex.inspect}, :timeout => #{timeout_value})") opts = { :timeout => timeout_value }.merge(opts) found = nil f = Fiber.current trace = caller timer = nil data_callback = nil matched = false started = Time.new timeout_proc = proc do data_callback && data_callback.cancel f.resume(TimeoutError.new("#{@host}: inactivity timeout (#{opts[:timeout]}) while waiting for #{strregex.inspect}; received: #{buffer.inspect}; waited total: #{Time.new - started}")) end data_callback = on(:data) do timer && timer.cancel if matched log.warn("data_callback invoked when already matched") next end if (matched = buffer.match(strregex)) log.debug("matched #{strregex.inspect} on #{buffer.inspect}") data_callback.cancel @buffer = matched.post_match f.resume(matched.pre_match + matched.to_s) else timer = EM::Timer.new(opts[:timeout], &timeout_proc) end end # Check against current buffer EM::next_tick { data_callback.call() if buffer.length > 0 } timer = EM::Timer.new(opts[:timeout], &timeout_proc) Fiber.yield.tap do |res| if res.is_a?(Exception) res.set_backtrace(Array(res.backtrace) + trace) raise res end yield(res) if block_given? end end |