em-ssh 0.0.3 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md CHANGED
@@ -96,7 +96,6 @@ See bin/em-ssh-shell for a more complex example usage of Shell.
96
96
  Em-ssh relies on Fibers. MRI 1.9.2-p290 on OSX Lion has been known to segfault when using Fibers.
97
97
 
98
98
 
99
-
100
99
  ##Copyright
101
100
  Copyright (c) 2011 Caleb Crane
102
101
 
data/bin/em-ssh-shell CHANGED
@@ -47,7 +47,7 @@ abort("command is required") if commands.empty?
47
47
 
48
48
 
49
49
  EM.run do
50
- EM::Ssh::Shell.new(host, options[:user], options[:password]) do |shell|
50
+ EM::Ssh::Shell.new(host, options[:user], options[:password], :net_ssh => options) do |shell|
51
51
  commands.each do |command|
52
52
  mys = shell.split
53
53
  mys.on(:closed) { info("#{mys} has closed") }
@@ -10,9 +10,8 @@ module EventMachine
10
10
  # Allows other objects to register callbacks with events that occur on a Ssh instance
11
11
  include Callbacks
12
12
 
13
- ##
14
- # Transport related
15
-
13
+ # maximum number of seconds to wait for a connection
14
+ TIMEOUT = 20
16
15
  # @return [String] The host to connect to, as given to the constructor.
17
16
  attr_reader :host
18
17
 
@@ -113,7 +112,10 @@ module EventMachine
113
112
  fire(:data, data)
114
113
  end
115
114
 
116
-
115
+ def connection_completed
116
+ @contimeout.cancel
117
+ @nocon.cancel
118
+ end # connection_completed
117
119
 
118
120
  def initialize(options = {})
119
121
  debug("#{self.class}.new(#{options})")
@@ -122,14 +124,18 @@ module EventMachine
122
124
  @password = options[:password]
123
125
  @queue = []
124
126
  @options = options
125
-
127
+ @timeout = options[:timeout] || TIMEOUT
128
+
126
129
  begin
127
130
  on(:connected, &options[:callback]) if options[:callback]
131
+ @nocon = on(:closed) { raise ConnectionFailed, @host }
132
+ @contimeout = EM::Timer.new(@timeout) { raise ConnectionTimeout, @host }
133
+
128
134
  @error_callback = lambda { |code| raise SshError.new(code) }
129
135
 
130
136
  @host_key_verifier = select_host_key_verifier(options[:paranoid])
131
137
  @server_version = ServerVersion.new(self)
132
- on(:version_negotiated) do
138
+ on(:version_negotiated) do
133
139
  @data.consume!(@server_version.header.length)
134
140
  @algorithms = Net::SSH::Transport::Algorithms.new(self, options)
135
141
 
@@ -142,8 +148,8 @@ module EventMachine
142
148
  if auth.authenticate("ssh-connection", user, options[:password])
143
149
  fire(:connected, Session.new(self, options))
144
150
  else
151
+ fire(:error, Net::SSH::AuthenticationFailed.new(user))
145
152
  close_connection
146
- raise Net::SSH::AuthenticationFailed, user
147
153
  end # auth.authenticate("ssh-connection", user, options[:password])
148
154
  end.resume # Fiber
149
155
  end # :algo_init
@@ -223,11 +229,10 @@ module EventMachine
223
229
  # @return [Callback] the callback that was registered
224
230
  def register_data_handler
225
231
  on(:data) do |data|
226
- # @todo instead of while use a EM.next_tick
227
- while (packet = @socket.poll_next_packet)
232
+ while (packet = @socket.poll_next_packet)
228
233
  case packet.type
229
234
  when DISCONNECT
230
- raise Net::SSH::Disconnect, "disconnected: #{packet[:description]} (#{packet[:reason_code]})"
235
+ close_connection
231
236
  when IGNORE
232
237
  debug("IGNORE packet received: #{packet[:data].inspect}")
233
238
  when UNIMPLEMENTED
@@ -236,8 +241,12 @@ module EventMachine
236
241
  log.send((packet[:always_display] ? :fatal : :debug), packet[:message])
237
242
  when KEXINIT
238
243
  Fiber.new do
239
- algorithms.accept_kexinit(packet)
240
- fire(:algo_init) if algorithms.initialized?
244
+ begin
245
+ algorithms.accept_kexinit(packet)
246
+ fire(:algo_init) if algorithms.initialized?
247
+ rescue Exception => e
248
+ fire(:error, e)
249
+ end # begin
241
250
  end.resume
242
251
  else
243
252
  @queue.push(packet)
data/lib/em-ssh/shell.rb CHANGED
@@ -32,8 +32,6 @@ module EventMachine
32
32
  attr_reader :shell
33
33
  # @return [Net::SSH::Connection]
34
34
  attr_reader :connection
35
- # @return [Boolean] Default (false) halt on timeout value - when true any timeouts will be halt the shell by raising an exception
36
- attr_reader :halt_on_timeout
37
35
  # @return [Hash] the options passed to initialize
38
36
  attr_reader :options
39
37
  # @return [Hash] the options to pass to connect automatically. They will be extracted from the opptions[:net_ssh] on initialization
@@ -62,11 +60,9 @@ module EventMachine
62
60
  # @param [String, nil] pass by default publickey and password auth will be attempted
63
61
  # @param [Hash] opts
64
62
  # @option opts [Hash] :net_ssh options to pass to Net::SSH; see Net::SSH.start
65
- # @option opts [Boolean] :halt_on_timeout (false)
66
63
  # @option opts [Fixnum] :timeout (TIMEOUT) default timeout for all #wait_for and #send_wait calls
67
64
  # @option opts [Boolean] :reconnect when disconnected reconnect
68
65
  def initialize(address, user, pass, opts = {}, &blk)
69
- @halt_on_timeout = opts[:halt_on_timeout] || false
70
66
  @timeout = opts[:timeout].is_a?(Fixnum) ? opts[:timeout] : TIMEOUT
71
67
  @host = address
72
68
  @user = user
@@ -76,7 +72,7 @@ module EventMachine
76
72
  @connection = opts[:connection]
77
73
  @parent = opts[:parent]
78
74
  @children = []
79
- @reconnect = opts[:reconnect]
75
+ @reconnect = opts[:reconnect]
80
76
 
81
77
  block_given? ? Fiber.new { open(&blk) }.resume : open
82
78
  end
@@ -118,7 +114,7 @@ module EventMachine
118
114
  # @param [String] send_str
119
115
  # @return [String] all data in the buffer including the wait_str if it was found
120
116
  def send_and_wait(send_str, wait_str = nil, opts = {})
121
- reconnect? ? connect : raise(Disconnected) unless connected?
117
+ reconnect? ? connect : raise(Disconnected) if !connected?
122
118
  raise ClosedChannel if closed?
123
119
  debug("send_and_wait(#{send_str.inspect}, #{wait_str.inspect}, #{opts})")
124
120
  send_data(send_str)
@@ -129,31 +125,37 @@ module EventMachine
129
125
  # @param [String, Regexp] strregex a string or regex to match the console output against.
130
126
  # @param [Hash] opts
131
127
  # @option opts [Fixnum] :timeout (Session::TIMEOUT) the maximum number of seconds to wait
132
- # @option opts [Boolean] (false) :halt_on_timeout
133
128
  # @return [String] the contents of the buffer
134
129
  def wait_for(strregex, opts = { })
135
130
  reconnect? ? connect : raise(Disconnected) unless connected?
136
131
  raise ClosedChannel if closed?
137
132
  debug("wait_for(#{strregex.inspect}, #{opts})")
138
- opts = { :timeout => @timeout, :halt_on_timeout => @halt_on_timeout }.merge(opts)
133
+ opts = { :timeout => @timeout }.merge(opts)
139
134
  buffer = ''
140
135
  found = nil
141
136
  f = Fiber.current
142
137
 
143
138
  timer = nil
144
139
  timeout = proc do
140
+ debug("timeout #{timer} fired")
141
+ shell.on_data {|c,d| }
142
+ begin
143
+ raise TimeoutError.new("#{host}: timeout while waiting for #{strregex.inspect}; received: #{buffer.inspect}")
144
+ rescue Exception => e
145
+ error(e)
146
+ debug(e.backtrace)
147
+ fire(:error, e)
148
+ end # begin
149
+ f.resume(nil)
145
150
  shell.on_data {|c,d| }
146
- # @todo fire an em errback
147
- if opts[:halt_on_timeout]
148
- raise TimeoutError("timeout while waiting for #{strregex.inspect}; received: #{buffer.inspect}")
149
- else
150
- warn("timeout while waiting for #{strregex.inspect}; received: #{buffer.inspect}")
151
- end # opts[:halt_on_timeout]
152
151
  end # timeout
153
152
 
154
153
  shell.on_data do |ch,data|
155
154
  buffer = "#{buffer}#{data}"
155
+ debug("data: #{buffer.dump}")
156
156
  if strregex.is_a?(Regexp) ? buffer.match(strregex) : buffer.include?(strregex)
157
+ debug("data matched")
158
+ debug("canceling timer #{timer}")
157
159
  timer.respond_to?(:cancel) && timer.cancel
158
160
  shell.on_data {|c,d| }
159
161
  f.resume(buffer)
@@ -161,6 +163,7 @@ module EventMachine
161
163
  end # |ch,data|
162
164
 
163
165
  timer = EM::Timer.new(opts[:timeout], &timeout)
166
+ debug("set timer: #{timer} for #{opts[:timeout]}")
164
167
  return Fiber.yield
165
168
  end # wait_for(strregex, opts = { })
166
169
 
@@ -169,8 +172,20 @@ module EventMachine
169
172
  # @return [self]
170
173
  def open(&blk)
171
174
  debug("open(#{blk})")
172
- f = Fiber.current
173
- connect unless connected?
175
+ f = Fiber.current
176
+
177
+ conerr = nil
178
+ unless connected?
179
+ conerr = on(:error) do |e|
180
+ error("#{e} (#{e.class})")
181
+ debug(e.backtrace)
182
+ conerr = e
183
+ f.resume(e)
184
+ end # |e|
185
+ connect
186
+ end # connected?
187
+
188
+ connection || raise(ConnectionError, "failed to create shell for #{host}: #{conerr} (#{conerr.class})")
174
189
 
175
190
  connection.open_channel do |channel|
176
191
  debug "**** channel open: #{channel}"
@@ -178,6 +193,7 @@ module EventMachine
178
193
  debug "***** pty open: #{pty}; suc: #{suc}"
179
194
  pty.send_channel_request("shell") do |shell,success|
180
195
  raise ConnectionError, "Failed to create shell." unless success
196
+ conerr && conerr.cancel
181
197
  debug "***** shell open: #{shell}"
182
198
  @shell = shell
183
199
  Fiber.new { yield(self) if block_given? }.resume
@@ -213,10 +229,11 @@ module EventMachine
213
229
  def connect
214
230
  return if connected?
215
231
  f = Fiber.current
216
- ::EM::Ssh.start(host, user, connect_opts) do |connection|
232
+ con = ::EM::Ssh.start(host, user, connect_opts) do |connection|
217
233
  @connection = connection
218
234
  f.resume
219
235
  end # |connection|
236
+ con.on(:error) { |e| fire(:error, e) }
220
237
  return Fiber.yield
221
238
  end # connect
222
239
 
@@ -231,6 +248,26 @@ module EventMachine
231
248
  end
232
249
 
233
250
 
251
+ def debug(msg = nil, &blk)
252
+ super("#{host} #{msg}", &blk)
253
+ end
254
+
255
+ def info(msg = nil, &blk)
256
+ super("#{host} #{msg}", &blk)
257
+ end
258
+
259
+ def fatal(msg = nil, &blk)
260
+ super("#{host} #{msg}", &blk)
261
+ end
262
+
263
+ def warn(msg = nil, &blk)
264
+ super("#{host} #{msg}", &blk)
265
+ end
266
+
267
+ def error(msg = nil, &blk)
268
+ super("#{host} #{msg}", &blk)
269
+ end
270
+
234
271
  end # class::Shell
235
272
  end # class::Ssh
236
273
  end # module::EventMachine
@@ -1,5 +1,5 @@
1
1
  module EventMachine
2
2
  class Ssh
3
- VERSION='0.0.3'
3
+ VERSION='0.1.0'
4
4
  end # class::Ssh
5
5
  end # module::EventMachine
data/lib/em-ssh.rb CHANGED
@@ -22,7 +22,9 @@ module EventMachine
22
22
  class SshError < Net::SSH::Exception; include Error; end
23
23
  class TimeoutError < Timeout::Error; include Error; end
24
24
  class ClosedChannel < SshError; end
25
- class DisconnectedChannel < SshError; end
25
+ class Disconnected < SshError; end
26
+ class ConnectionFailed < SshError; end
27
+ class ConnectionTimeout < ConnectionFailed; end
26
28
 
27
29
 
28
30
  class << self
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: em-ssh
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,12 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-10-24 00:00:00.000000000 +09:00
13
- default_executable:
12
+ date: 2011-10-30 00:00:00.000000000Z
14
13
  dependencies:
15
14
  - !ruby/object:Gem::Dependency
16
15
  name: eventmachine
17
- requirement: &2160452560 !ruby/object:Gem::Requirement
16
+ requirement: &70168320140920 !ruby/object:Gem::Requirement
18
17
  none: false
19
18
  requirements:
20
19
  - - ! '>='
@@ -22,10 +21,10 @@ dependencies:
22
21
  version: '0'
23
22
  type: :runtime
24
23
  prerelease: false
25
- version_requirements: *2160452560
24
+ version_requirements: *70168320140920
26
25
  - !ruby/object:Gem::Dependency
27
26
  name: net-ssh
28
- requirement: &2160424600 !ruby/object:Gem::Requirement
27
+ requirement: &70168320140460 !ruby/object:Gem::Requirement
29
28
  none: false
30
29
  requirements:
31
30
  - - ! '>='
@@ -33,10 +32,10 @@ dependencies:
33
32
  version: '0'
34
33
  type: :runtime
35
34
  prerelease: false
36
- version_requirements: *2160424600
35
+ version_requirements: *70168320140460
37
36
  - !ruby/object:Gem::Dependency
38
37
  name: ruby-termios
39
- requirement: &2160412880 !ruby/object:Gem::Requirement
38
+ requirement: &70168320140040 !ruby/object:Gem::Requirement
40
39
  none: false
41
40
  requirements:
42
41
  - - ! '>='
@@ -44,10 +43,10 @@ dependencies:
44
43
  version: '0'
45
44
  type: :development
46
45
  prerelease: false
47
- version_requirements: *2160412880
46
+ version_requirements: *70168320140040
48
47
  - !ruby/object:Gem::Dependency
49
48
  name: highline
50
- requirement: &2160402840 !ruby/object:Gem::Requirement
49
+ requirement: &70168320139620 !ruby/object:Gem::Requirement
51
50
  none: false
52
51
  requirements:
53
52
  - - ! '>='
@@ -55,7 +54,7 @@ dependencies:
55
54
  version: '0'
56
55
  type: :development
57
56
  prerelease: false
58
- version_requirements: *2160402840
57
+ version_requirements: *70168320139620
59
58
  description: ''
60
59
  email:
61
60
  - em-ssh@simulacre.org
@@ -78,7 +77,6 @@ files:
78
77
  - bin/em-ssh
79
78
  - bin/em-ssh-shell
80
79
  - README.md
81
- has_rdoc: true
82
80
  homepage: http://github.com/simulacre/em-ssh
83
81
  licenses:
84
82
  - MIT
@@ -100,8 +98,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
100
98
  version: 1.3.6
101
99
  requirements: []
102
100
  rubyforge_project:
103
- rubygems_version: 1.6.2
101
+ rubygems_version: 1.8.10
104
102
  signing_key:
105
103
  specification_version: 3
106
104
  summary: An EventMachine compatible net-ssh
107
105
  test_files: []
106
+ has_rdoc: