em-ssh 0.0.3 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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: