diff options
Diffstat (limited to 'pkg/net-ssh-multi-1.1/lib/net/ssh/multi/channel.rb')
-rw-r--r-- | pkg/net-ssh-multi-1.1/lib/net/ssh/multi/channel.rb | 230 |
1 files changed, 230 insertions, 0 deletions
diff --git a/pkg/net-ssh-multi-1.1/lib/net/ssh/multi/channel.rb b/pkg/net-ssh-multi-1.1/lib/net/ssh/multi/channel.rb new file mode 100644 index 0000000..34bd117 --- /dev/null +++ b/pkg/net-ssh-multi-1.1/lib/net/ssh/multi/channel.rb @@ -0,0 +1,230 @@ +module Net; module SSH; module Multi + # Net::SSH::Multi::Channel encapsulates a collection of Net::SSH::Connection::Channel + # instances from multiple different connections. It allows for operations to + # be performed on all contained channels, simultaneously, using an interface + # mostly identical to Net::SSH::Connection::Channel itself. + # + # You typically obtain a Net::SSH::Multi::Channel instance via + # Net::SSH::Multi::Session#open_channel or Net::SSH::Multi::Session#exec, + # though there is nothing stopping you from instantiating one yourself with + # a handful of Net::SSH::Connection::Channel objects (though they should be + # associated with connections managed by a Net::SSH::Multi::Session object + # for consistent behavior). + # + # channel = session.open_channel do |ch| + # # ... + # end + # + # channel.wait + class Channel + include Enumerable + + # The Net::SSH::Multi::Session instance that controls this channel collection. + attr_reader :connection + + # The collection of Net::SSH::Connection::Channel instances that this multi-channel aggregates. + attr_reader :channels + + # A Hash of custom properties that may be set and queried on this object. + attr_reader :properties + + # Instantiate a new Net::SSH::Multi::Channel instance, controlled by the + # given +connection+ (a Net::SSH::Multi::Session object) and wrapping the + # given +channels+ (Net::SSH::Connection::Channel instances). + # + # You will typically never call this directly; rather, you'll get your + # multi-channel references via Net::SSH::Multi::Session#open_channel and + # friends. + def initialize(connection, channels) + @connection = connection + @channels = channels + @properties = {} + end + + # Iterate over each component channel object, yielding each in order to the + # associated block. + def each + @channels.each { |channel| yield channel } + end + + # Retrieve the property (see #properties) with the given +key+. + # + # host = channel[:host] + def [](key) + @properties[key] + end + + # Set the property (see #properties) with the given +key+ to the given + # +value+. + # + # channel[:visited] = true + def []=(key, value) + @properties[key] = value + end + + # Perform an +exec+ command on all component channels. The block, if given, + # is passed to each component channel, so it will (potentially) be invoked + # once for every channel in the collection. The block will receive two + # parameters: the specific channel object being operated on, and a boolean + # indicating whether the exec succeeded or not. + # + # channel.exec "ls -l" do |ch, success| + # # ... + # end + # + # See the documentation in Net::SSH for Net::SSH::Connection::Channel#exec + # for more information on how to work with the callback. + def exec(command, &block) + channels.each { |channel| channel.exec(command, &block) } + self + end + + # Perform a +request_pty+ command on all component channels. The block, if + # given, is passed to each component channel, so it will (potentially) be + # invoked once for every channel in the collection. The block will + # receive two parameters: the specific channel object being operated on, + # and a boolean indicating whether the pty request succeeded or not. + # + # channel.request_pty do |ch, success| + # # ... + # end + # + # See the documentation in Net::SSH for + # Net::SSH::Connection::Channel#request_pty for more information on how to + # work with the callback. + def request_pty(opts={}, &block) + channels.each { |channel| channel.request_pty(opts, &block) } + self + end + + # Send the given +data+ to each component channel. It will be sent to the + # remote process, typically being received on the process' +stdin+ stream. + # + # channel.send_data "password\n" + def send_data(data) + channels.each { |channel| channel.send_data(data) } + self + end + + # Returns true as long as any of the component channels are active. + # + # connection.loop { channel.active? } + def active? + channels.any? { |channel| channel.active? } + end + + # Runs the connection's event loop until the channel is no longer active + # (see #active?). + # + # channel.exec "something" + # channel.wait + def wait + connection.loop { active? } + self + end + + # Closes all component channels. + def close + channels.each { |channel| channel.close } + self + end + + # Tells the remote process for each component channel not to expect any + # further data from this end of the channel. + def eof! + channels.each { |channel| channel.eof! } + self + end + + # Registers a callback on all component channels, to be invoked when the + # remote process emits data (usually on its +stdout+ stream). The block + # will be invoked with two arguments: the specific channel object, and the + # data that was received. + # + # channel.on_data do |ch, data| + # puts "got data: #{data}" + # end + def on_data(&block) + channels.each { |channel| channel.on_data(&block) } + self + end + + # Registers a callback on all component channels, to be invoked when the + # remote process emits "extended" data (typically on its +stderr+ stream). + # The block will be invoked with three arguments: the specific channel + # object, an integer describing the data type (usually a 1 for +stderr+) + # and the data that was received. + # + # channel.on_extended_data do |ch, type, data| + # puts "got extended data: #{data}" + # end + def on_extended_data(&block) + channels.each { |channel| channel.on_extended_data(&block) } + self + end + + # Registers a callback on all component channels, to be invoked during the + # idle portion of the connection event loop. The callback will be invoked + # with one argument: the specific channel object being processed. + # + # channel.on_process do |ch| + # # ... + # end + def on_process(&block) + channels.each { |channel| channel.on_process(&block) } + self + end + + # Registers a callback on all component channels, to be invoked when the + # remote server terminates the channel. The callback will be invoked + # with one argument: the specific channel object being closed. + # + # channel.on_close do |ch| + # # ... + # end + def on_close(&block) + channels.each { |channel| channel.on_close(&block) } + self + end + + # Registers a callback on all component channels, to be invoked when the + # remote server has no further data to send. The callback will be invoked + # with one argument: the specific channel object being marked EOF. + # + # channel.on_eof do |ch| + # # ... + # end + def on_eof(&block) + channels.each { |channel| channel.on_eof(&block) } + self + end + + # Registers a callback on all component channels, to be invoked when the + # remote server is unable to open the channel. The callback will be + # invoked with three arguments: the channel object that couldn't be + # opened, a description of the error (as a string), and an integer code + # representing the error. + # + # channel.on_open_failed do |ch, description, code| + # # ... + # end + def on_open_failed(&block) + channels.each { |channel| channel.on_open_failed(&block) } + self + end + + # Registers a callback on all component channels, to be invoked when the + # remote server sends a channel request of the given +type+. The callback + # will be invoked with two arguments: the specific channel object receiving + # the request, and a Net::SSH::Buffer instance containing the request-specific + # data. + # + # channel.on_request("exit-status") do |ch, data| + # puts "exited with #{data.read_long}" + # end + def on_request(type, &block) + channels.each { |channel| channel.on_request(type, &block) } + self + end + end +end; end; end
\ No newline at end of file |