pry-remote-em 0.6.3 → 0.7.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
@@ -38,7 +38,7 @@ program to connect itself to it:
38
38
 
39
39
  You can then connect to the pry session using ``pry-remote-em``:
40
40
 
41
- $ pry-remote-em
41
+ $ pry-remote-em pryem://127.0.0.1:6462/
42
42
  [pry-remote-em] client connected to pryem://127.0.0.1:6462/
43
43
  [pry-remote-em] remote is PryRemoteEm 0.1.0
44
44
  [1] pry(#<Foo>)> stat
@@ -69,7 +69,7 @@ You can then connect to the pry session using ``pry-remote-em``:
69
69
  [7] pry(#<Foo>)> exit
70
70
  [pry-remote-em] session terminated
71
71
 
72
- $ pry-remote-em
72
+ $ pry-remote-em pryem://127.0.0.1:6462/
73
73
  [pry-remote-em] client connected to pryem://127.0.0.1:6462/
74
74
  [pry-remote-em] remote is PryRemoteEm 0.1.0
75
75
  [1] pry(#<Foo>)> x
@@ -110,7 +110,8 @@ EM.run {
110
110
  [pry-remote-em] listening for connections on pryem://localhost:6466/
111
111
 
112
112
  ```shell
113
- $ pry-remote-em
113
+
114
+ $ pry-remote-em pryem://127.0.0.1:6462/
114
115
  [pry-remote-em] client connected to pryem://127.0.0.1:6462/
115
116
  [pry-remote-em] remote is PryRemoteEm 0.4.0 pryem
116
117
  [1] pry("pretty_print")>
@@ -136,6 +137,88 @@ $ pry-remote-em pryem://127.0.0.1:6466/
136
137
  [1] pry(#<RubyVM::InstructionSequence>)>
137
138
  ```
138
139
 
140
+ ## Server Broker
141
+
142
+ When more than one server is running on a given host and each server is
143
+ started with :auto it can be time consuming to manually figure out which
144
+ port each server is running on. The Broker which listens on port 6461
145
+ keeps track of which server is running on which port.
146
+
147
+ By default the pry-remote-em cli utility will connect to the broker and
148
+ retrieve a list of known servers. You can then select one to connect to
149
+ by its id, name or url. You can also choose to proxy your connection
150
+ through the broker to the selected server.
151
+
152
+ ```shell
153
+
154
+ $ bin/pry-remote-em
155
+ [pry-remote-em] client connected to pryem://127.0.0.1:6461/
156
+ [pry-remote-em] remote is PryRemoteEm 0.7.0 pryem
157
+ -----------------------------------------------------------------------------
158
+ | id | name | url |
159
+ -----------------------------------------------------------------------------
160
+ | 1 | #<#<Class:0x007f924b9bbee8>> | pryem://127.0.0.1:6462/ |
161
+ | 2 | #<Foo> | pryem://127.0.0.1:1337/ |
162
+ | 3 | #<#<Class:0x007f924b9bbee8>> | pryems://127.0.0.1:6463/ |
163
+ | 4 | #<#<Class:0x007f924b9bbee8>> | pryems://127.0.0.1:6464/ |
164
+ | 5 | #<#<Class:0x007f924b9bbee8>> | pryems://127.0.0.1:6465/ |
165
+ | 6 | #<#<Class:0x007f924b9bbee8>> | pryems://127.0.0.1:6466/ |
166
+ | 7 | #<#<Class:0x007f924b9bbee8>> | pryems://127.0.0.1:6467/ |
167
+ | 8 | #<#<Class:0x007f924b9bbee8>> | pryem://127.0.0.1:6468/ |
168
+ | 9 | #<#<Class:0x007f924b9bbee8>> | pryem://127.0.0.1:6469/ |
169
+ -----------------------------------------------------------------------------
170
+ (q) to quit; (r) to refresh (p) to proxy
171
+ connect to: 3
172
+ [pry-remote-em] client connected to pryem://127.0.0.1:6463/
173
+ [pry-remote-em] remote is PryRemoteEm 0.7.0 pryems
174
+ [pry-remote-em] negotiating TLS
175
+ [pry-remote-em] TLS connection established
176
+ [1] pry(#<#<Class:0x007f924b9bbee8>>)>
177
+ ```
178
+
179
+ By default the Broker will listen on 127.0.0.1:6461. To change the ip
180
+ address that the Broker binds to specify it in a PRYEMBROKER environment
181
+ variable, or in :broker_host option passed to #remote_pry_em.
182
+
183
+ ```shell
184
+
185
+ $ PRYEMBROKER=0.0.0.0 be ./test/service.rb
186
+ I, [2012-07-13T21:10:00.936993 #88528] INFO -- : [pry-remote-em] listening for connections on pryem://0.0.0.0:6462/
187
+ I, [2012-07-13T21:10:00.937132 #88528] INFO -- : [pry-remote-em broker] listening on pryem://0.0.0.0:6461
188
+ I, [2012-07-13T21:10:00.937264 #88528] INFO -- : [pry-remote-em] listening for connections on pryem://0.0.0.0:1337/
189
+ I, [2012-07-13T21:10:00.937533 #88528] INFO -- : [pry-remote-em] listening for connections on pryems://0.0.0.0:6463/
190
+ I, [2012-07-13T21:10:00.937804 #88528] INFO -- : [pry-remote-em] listening for connections on pryems://0.0.0.0:6464/
191
+ I, [2012-07-13T21:10:00.938126 #88528] INFO -- : [pry-remote-em] listening for connections on pryems://0.0.0.0:6465/
192
+ I, [2012-07-13T21:10:00.938471 #88528] INFO -- : [pry-remote-em] listening for connections on pryems://0.0.0.0:6466/
193
+ I, [2012-07-13T21:10:00.938835 #88528] INFO -- : [pry-remote-em] listening for connections on pryems://0.0.0.0:6467/
194
+ I, [2012-07-13T21:10:00.939230 #88528] INFO -- : [pry-remote-em] listening for connections on pryem://0.0.0.0:6468/
195
+ I, [2012-07-13T21:10:00.939640 #88528] INFO -- : [pry-remote-em] listening for connections on pryem://0.0.0.0:6469/
196
+ I, [2012-07-13T21:10:01.031576 #88528] INFO -- : [pry-remote-em broker] received client connection from 127.0.0.1:62288
197
+ I, [2012-07-13T21:10:01.031931 #88528] INFO -- : [pry-remote-em] client connected to pryem://127.0.0.1:6461/
198
+ I, [2012-07-13T21:10:01.032120 #88528] INFO -- : [pry-remote-em] remote is PryRemoteEm 0.7.0 pryem
199
+ I, [2012-07-13T21:10:01.032890 #88528] INFO -- : [pry-remote-em broker] registered pryem://127.0.0.1:6462/ - "#<#<Class:0x007f924b9bbee8>>"
200
+ I, [2012-07-13T21:10:01.125123 #88528] INFO -- : [pry-remote-em broker] registered pryem://127.0.0.1:6469/ - "#<#<Class:0x007f924b9bbee8>>"
201
+ I, [2012-07-13T21:10:01.125487 #88528] INFO -- : [pry-remote-em broker] registered pryems://127.0.0.1:6467/ - "#<#<Class:0x007f924b9bbee8>>"
202
+ I, [2012-07-13T21:10:01.490729 #88528] INFO -- : [pry-remote-em broker] registered pryems://127.0.0.1:6464/ - "#<#<Class:0x007f924b9bbee8>>"
203
+ I, [2012-07-13T21:10:01.583015 #88528] INFO -- : [pry-remote-em broker] registered pryem://127.0.0.1:1337/ - "#<Foo>"
204
+ I, [2012-07-13T21:10:01.674842 #88528] INFO -- : [pry-remote-em broker] registered pryems://127.0.0.1:6466/ - "#<#<Class:0x007f924b9bbee8>>"
205
+ I, [2012-07-13T21:10:01.766813 #88528] INFO -- : [pry-remote-em broker] registered pryem://127.0.0.1:6468/ - "#<#<Class:0x007f924b9bbee8>>"
206
+ I, [2012-07-13T21:10:01.858423 #88528] INFO -- : [pry-remote-em broker] registered pryems://127.0.0.1:6465/ - "#<#<Class:0x007f924b9bbee8>>"
207
+ ```
208
+
209
+ It is possible to have a pry-remote-em server register with a Broker
210
+ running on a different host. Just specify the Brokers address in the
211
+ PRYEMBROKER environment variable or the :broker_host option passed to #remote_pry_em.
212
+
213
+ To connect to a broker running on a seperate host with the cli client
214
+ just specify it on the command line ``bin/pry-remote-em preym://10.0.0.2:6461/``.
215
+ You can then proxy your client connections to remote servers through
216
+ that Broker.
217
+
218
+ The Broker will not run in TLS mode, but it can proxy connections to a
219
+ TLS enabled server.
220
+
221
+
139
222
  ## TLS Encryption
140
223
 
141
224
  When creating a server pass the :tls => true option to enable TLS.
@@ -369,9 +452,7 @@ E, [2012-02-11T19:23:40.770380 #36471] ERROR -- : refused to execute shell comma
369
452
 
370
453
  # Missing Features
371
454
 
372
- - AutoDiscovery/Broker [ticket](https://github.com/simulacre/pry-remote-em/issues/11)
373
455
  - HTTP Transport [ticket](https://github.com/simulacre/pry-remote-em/issues/12)
374
- - Vi mode editing - RbReadline doesn't support vi edit mode. I'm looking into contributing it. PryRemoteEm uses rb-readline because the STLIB version doesn't play nice with Fibers.
375
456
  - Ssh key based authentication
376
457
 
377
458
 
@@ -4,10 +4,10 @@ require 'uri'
4
4
  require 'highline'
5
5
  require 'pry-remote-em/client'
6
6
 
7
- uri = ARGV[0] || "pryem://localhost:#{PryRemoteEm::DEFPORT}"
7
+ uri = ARGV[0] || "pryem://localhost:#{PryRemoteEm::DEF_BROKERPORT}"
8
8
  uri = URI.parse(uri)
9
9
  unless %w(pryem pryems).include?(uri.scheme)
10
- abort "only pryem URIs are currently supported\n usage: pryem(s)://127.0.0.1:#{PryRemoteEm::DEFPORT}"
10
+ abort "only pryem URIs are currently supported\n usage: pryem(s)://127.0.0.1:#{PryRemoteEm::DEF_BROKERPORT}"
11
11
  end
12
12
 
13
13
  tried = 0
@@ -4,16 +4,18 @@ rescue LoadError
4
4
  warn "OpenSSL support is not available"
5
5
  end
6
6
  require 'pry-remote-em/version'
7
- require 'pry-remote-em/json-proto'
7
+ require 'pry-remote-em/proto'
8
8
  require 'eventmachine'
9
9
  require 'socket'
10
- require 'json'
11
- require "fiber"
10
+ require 'fiber'
11
+ require 'uri'
12
12
 
13
13
  module PryRemoteEm
14
- DEFHOST = 'localhost'
15
- DEFPORT = 6462
16
- NEGOTIMER = 15
14
+ DEFHOST = 'localhost'
15
+ DEFPORT = 6462
16
+ DEF_BROKERPORT = DEFPORT - 1
17
+ DEF_BROKERHOST = 'localhost'
18
+ NEGOTIMER = 15
17
19
  end
18
20
 
19
21
 
@@ -0,0 +1,189 @@
1
+ require 'pry-remote-em'
2
+ require 'pry-remote-em/client/broker'
3
+ require 'pry-remote-em/client/proxy'
4
+
5
+ module PryRemoteEm
6
+ module Broker
7
+ class << self
8
+ attr_reader :listening, :host, :port
9
+ alias :listening? :listening
10
+
11
+ def run(host = ENV['PRYEMBROKER'] || DEF_BROKERHOST, port = ENV['PRYEMBROKERPORT'] || DEF_BROKERPORT, opts = {:tls => false})
12
+ raise "root permission required for port below 1024 (#{port})" if port < 1024 && Process.euid != 0
13
+ @host = host
14
+ @port = port
15
+ # Brokers cannot use SSL directly. If they do then when a proxy request to an SSL server is received
16
+ # the client and server will not be able to negotiate a SSL session. The proxied traffic can be SSL
17
+ # encrypted, but the SSL session will be between the client and the server.
18
+ opts = opts.dup
19
+ opts[:tls] = false
20
+ @opts = opts
21
+ begin
22
+ EM.start_server(host, port, PryRemoteEm::Broker, opts) do |broker|
23
+ end
24
+ log.info("[pry-remote-em broker] listening on #{opts[:tls] ? 'pryems' : 'pryem'}://#{host}:#{port}")
25
+ @listening = true
26
+ rescue => e
27
+ # EM 1.0.0.beta4's message tells us the port is in use; 0.12.10 just says, 'no acceptor'
28
+ if (e.message.include?('port is in use') || e.message.include?('no acceptor'))
29
+ # [pry-remote-em broker] a broker is already listening on #{host}:#{port}
30
+ else
31
+ raise e
32
+ end
33
+ end
34
+ end
35
+
36
+ def restart
37
+ log.info("[pry-remote-em broker] restarting on pryem://#{host}:#{port}")
38
+ run(@host, @port, @opts)
39
+ EM::Timer.new(rand(0.9)) do
40
+ PryRemoteEm.servers.each do |url, (sig, name)|
41
+ next unless EM.get_sockname(sig)
42
+ register(url, name)
43
+ end
44
+ end
45
+ @waiting = nil
46
+ @client = nil
47
+ end
48
+
49
+ def opts
50
+ @opts ||= {}
51
+ end
52
+
53
+ def log
54
+ return opts[:logger] if opts[:logger]
55
+ @log ||= Logger.new(STDERR)
56
+ end
57
+
58
+ def servers
59
+ @servers ||= {}
60
+ end
61
+
62
+ def register(url, name = 'unknown')
63
+ client { |c| c.send_register_server(url, name) }
64
+ end
65
+
66
+ def unregister(server)
67
+ client {|c| c.send_unregister_server(server) }
68
+ end
69
+
70
+ def watch_heartbeats(url)
71
+ return if timers[url]
72
+ timers[url] = EM::PeriodicTimer.new(20) do
73
+ if !hbeats[url] || (Time.new - hbeats[url]) > 20
74
+ servers.delete(url)
75
+ timers[url].cancel
76
+ timers.delete(url)
77
+ end
78
+ end
79
+ end
80
+
81
+ def timers
82
+ @timers ||= {}
83
+ end
84
+
85
+ def hbeats
86
+ @hbeats ||= {}
87
+ end
88
+
89
+ def connected?
90
+ @connected
91
+ end
92
+
93
+ private
94
+
95
+ def client(&blk)
96
+ raise ArgumentError.new("A block is required") unless block_given?
97
+ if @client
98
+ yield @client
99
+ return
100
+ end
101
+
102
+ if @waiting
103
+ @waiting << blk
104
+ else
105
+ @waiting = []
106
+ EM.connect(host, port, Client::Broker, @opts) do |client|
107
+ client.errback { |e| raise(e || "broker client error") }
108
+ client.callback do
109
+ @client = client
110
+ while (w = @waiting.shift)
111
+ w.call(client)
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end # class << self
118
+
119
+ include Proto
120
+
121
+ def receive_server_list
122
+ send_server_list(Broker.servers)
123
+ end
124
+
125
+ def receive_register_server(url, name)
126
+ url = URI.parse(url)
127
+ url.host = peer_ip if ['0.0.0.0', 'localhost', '127.0.0.1'].include?(url.host)
128
+ log.info("[pry-remote-em broker] registered #{url} - #{name.inspect}") unless Broker.servers[url] == name
129
+ Broker.servers[url] = name
130
+ Broker.hbeats[url] = Time.new
131
+ Broker.watch_heartbeats(url)
132
+ name
133
+ end
134
+
135
+ def receive_unregister_server(url)
136
+ url = URI.parse(url)
137
+ url.host = peer_ip if ['0.0.0.0', 'localhost', '127.0.0.1'].include?(url.host)
138
+ log.warn("[pry-remote-em broker] unregister #{url}")
139
+ Broker.servers.delete(url)
140
+ end
141
+
142
+ def receive_proxy_connection(url)
143
+ log.info("[pry-remote-em broker] proxying to #{url}")
144
+ url = URI.parse(url)
145
+ EM.connect(url.host, url.port, Client::Proxy, self)
146
+ end
147
+
148
+ def initialize(opts = {:tls => false}, &blk)
149
+ @opts = opts
150
+ end
151
+
152
+ def log
153
+ Broker.log
154
+ end
155
+
156
+ def post_init
157
+ port, ip = Socket.unpack_sockaddr_in(get_peername)
158
+ log.info("[pry-remote-em broker] received client connection from #{ip}:#{port}")
159
+ send_banner("PryRemoteEm #{VERSION} #{@opts[:tls] ? 'pryems' : 'pryem'}")
160
+ @opts[:tls] ? start_tls : send_server_list(Broker.servers)
161
+ end
162
+
163
+ def start_tls
164
+ log.debug("[pry-remote-em broker] starting TLS (#{peer_ip}:#{peer_port})")
165
+ send_start_tls
166
+ super(@opts[:tls].is_a?(Hash) ? @opts[:tls] : {})
167
+ end
168
+
169
+ def peer_ip
170
+ return @peer_ip if @peer_ip
171
+ return "" if get_peername.nil?
172
+ @peer_port, @peer_ip = Socket.unpack_sockaddr_in(get_peername)
173
+ @peer_ip
174
+ end
175
+
176
+ def peer_port
177
+ return @peer_port if @peer_port
178
+ return "" if get_peername.nil?
179
+ @peer_port, @peer_ip = Socket.unpack_sockaddr_in(get_peername)
180
+ @peer_port
181
+ end
182
+
183
+ def ssl_handshake_completed
184
+ log.info("[pry-remote-em broker] TLS connection established (#{peer_ip}:#{peer_port})")
185
+ send_server_list(Broker.servers)
186
+ end
187
+
188
+ end # module::Broker
189
+ end # module::PryRemoteEm
@@ -1,17 +1,19 @@
1
1
  require 'uri'
2
2
  require 'pry-remote-em'
3
- require 'pry-remote-em/client/keyboard'
3
+ begin
4
+ require 'pry-remote-em/client/keyboard'
5
+ rescue LoadError => e
6
+ warn "[pry-remote-em] unable to load keyboard depenencies (termios); interactive shell commands disabled"
7
+ end
8
+ require "pry-remote-em/client/generic"
4
9
  require 'pry/helpers/base_helpers'
5
- #require "readline" # doesn't work with Fiber.yield
6
- # - /Users/caleb/src/pry-remote-em/lib/pry-remote-em/client.rb:45:in `yield': fiber called across stack rewinding barrier (FiberError)
7
- require "rb-readline" # doesn't provide vi-mode support :(
8
- # https://github.com/luislavena/rb-readline/issues/21
9
- # https://github.com/simulacre/rb-readline/commit/0376eb4e9526b3dc1a6512716322efcef409628d
10
+ require "readline"
11
+ require 'highline'
10
12
 
11
13
  module PryRemoteEm
12
14
  module Client
13
15
  include EM::Deferrable
14
- include JsonProto
16
+ include Client::Generic
15
17
  include Pry::Helpers::BaseHelpers
16
18
 
17
19
  class << self
@@ -19,7 +21,7 @@ module PryRemoteEm
19
21
  EM.connect(host || PryRemoteEm::DEFHOST, port || PryRemoteEm::DEFPORT, PryRemoteEm::Client, opts) do |c|
20
22
  c.callback { yield if block_given? }
21
23
  c.errback do |e|
22
- puts "[pry-remote-em] connection failed\n#{e}"
24
+ Kernel.puts "[pry-remote-em] connection failed\n#{e}"
23
25
  yield(e) if block_given?
24
26
  end
25
27
  end
@@ -38,117 +40,182 @@ module PryRemoteEm
38
40
  end
39
41
 
40
42
  def post_init
41
- if get_peername
42
- port, ip = Socket.unpack_sockaddr_in(get_peername)
43
- Kernel.puts "[pry-remote-em] client connected to pryem://#{ip}:#{port}/"
44
- else
45
- # TODO use the args used to create this connection
46
- Kernel.puts "[pry-remote-em] client connected"
47
- end
48
- @nego_timer = EM::Timer.new(PryRemoteEm::NEGOTIMER) do
49
- fail("[pry-remote-em] server didn't finish negotiation within #{PryRemoteEm::NEGOTIMER} seconds; terminating")
50
- end
51
43
  Readline.completion_proc = method(:auto_complete)
52
44
  end
53
45
 
54
- def auto_complete(word)
55
- @waiting = Fiber.current
56
- send_data({:c => word})
57
- return Fiber.yield
46
+ def ssl_handshake_completed
47
+ log.info("[pry-remote-em] TLS connection established")
48
+ @opts[:tls] = true
58
49
  end
59
50
 
60
- def receive_json(j)
61
- if j['p'] # prompt
62
- readline(j['p'])
63
-
64
- elsif j['d'] # printable data
65
- stagger_output j['d'], $stdout # Pry::Helpers::BaseHelpers
66
-
67
- elsif j['m']
68
- Kernel.puts "\033[1m! msg: " + j['m'] + "\033[0m"
51
+ def unbind
52
+ if (uri = @reconnect_to)
53
+ @reconnect_to = nil
54
+ tls = uri.scheme == 'pryems'
55
+ log.info("\033[35m[pry-remote-em] connection will not be encrypted\033[0m") if @opts[:tls] && !tls
56
+ @opts[:tls] = tls
57
+ @tls_started = false
58
+ reconnect(uri.host, uri.port)
59
+ else
60
+ @unbound = true
61
+ log.info("[pry-remote-em] session terminated")
62
+ # prior to 1.0.0.b4 error? returns true here even when it's not
63
+ return succeed if Gem.loaded_specs["eventmachine"].version < Gem::Version.new("1.0.0.beta4")
64
+ error? ? fail : succeed
65
+ end
66
+ end
69
67
 
70
- elsif j['mb']
71
- Kernel.puts "\033[1m!! msg: " + j['mb'] + "\033[0m"
68
+ def receive_banner(name, version, scheme)
69
+ # Client::Generic#receive_banner
70
+ if super(name, version, scheme)
71
+ start_tls if @opts[:tls]
72
+ end
73
+ end
72
74
 
73
- elsif j['s'] # shell command output
74
- Kernel.puts j['s']
75
+ def receive_server_list(list)
76
+ if list.empty?
77
+ log.info("\033[33m[pry-remote-em] no servers are registered with the broker\033[0m")
78
+ Process.exit
79
+ end
80
+ choice, proxy = choose_server(list)
81
+ return unless choice
82
+ uri, name = URI.parse(choice[0]), choice[1]
83
+ if proxy
84
+ @opts[:tls] = uri.scheme == 'pryems'
85
+ @negotiated = false
86
+ @tls_started = false
87
+ return send_proxy_connection(uri)
88
+ end
89
+ @reconnect_to = uri
90
+ close_connection
91
+ end
75
92
 
76
- elsif j.include?('sc') # command completed
77
- if @keyboard
78
- @keyboard.bufferio(true)
79
- @keyboard.close_connection
93
+ def choose_server(list)
94
+ highline = HighLine.new
95
+ proxy = false
96
+ choice = nil
97
+ nm_col_len = list.values.map(&:length).sort[-1] + 5
98
+ ur_col_len = list.keys.map(&:length).sort[-1] + 5
99
+ header = sprintf("| %-3s | %-#{nm_col_len}s | %-#{ur_col_len}s |", "id", "name", "url")
100
+ border = ("-" * header.length)
101
+ table = [border, header, border]
102
+ list = list.to_a
103
+ list.each_with_index do |(url, name), idx|
104
+ table << sprintf("| %-2d | %-#{nm_col_len}s | %-#{ur_col_len}s |", idx + 1, name, url)
105
+ end
106
+ table << border
107
+ table = table.join("\n")
108
+ Kernel.puts table
109
+ while choice.nil?
110
+ if proxy
111
+ question = "(q) to quit; (r) to refresh (c) to connect\nproxy to: "
112
+ else
113
+ question = "(q) to quit; (r) to refresh (p) to proxy\nconnect to: "
80
114
  end
81
-
82
- elsif j['g'] # server banner
83
- Kernel.puts "[pry-remote-em] remote is #{j['g']}"
84
- name, version, scheme = j['g'].split(" ", 3)
85
- # TODO parse version and compare against a Gem style matcher
86
- # https://github.com/simulacre/pry-remote-em/issues/21
87
- return fail("[pry-remote-em] incompatible version #{version}") if version != PryRemoteEm::VERSION
88
- if scheme.nil? || scheme != (reqscheme = @opts[:tls] ? 'pryems' : 'pryem')
89
- if scheme == 'pryems' && defined?(::OpenSSL)
90
- @opts[:tls] = true
91
- else
92
- return fail("[pry-remote-em] server doesn't support required scheme #{reqscheme.dump}")
93
- end # scheme == 'pryems' && defined?(::OpenSSL)
115
+ choice = highline.ask(question)
116
+ return close_connection if ['q', 'quit', 'exit'].include?(choice.downcase)
117
+ if ['r', 'reload', 'refresh'].include?(choice.downcase)
118
+ send_server_list
119
+ return nil
94
120
  end
95
- @nego_timer.cancel
96
- @negotiated = true
97
- start_tls if @opts[:tls]
121
+ if ['c', 'connect'].include?(choice.downcase)
122
+ proxy = false
123
+ choice = nil
124
+ next
125
+ end
126
+ if ['p', 'proxy'].include?(choice.downcase)
127
+ proxy = true
128
+ choice = nil
129
+ next
130
+ end
131
+ choice = choice.to_i.to_s == choice ?
132
+ list[choice.to_i - 1] :
133
+ list.find{|(url, name)| url == choice || name == choice }
134
+ end
135
+ [choice, proxy]
136
+ end
98
137
 
99
- elsif j['c'] # tab completion response
100
- @waiting, f = nil, @waiting
101
- f.resume(j['c']) if f
138
+ def receive_auth(a)
139
+ return fail a if a.is_a?(String)
140
+ return authenticate if a == false
141
+ @authenticated = true if a == true
142
+ end
102
143
 
103
- elsif j.include?('a') # authentication demand
104
- return fail j['a'] if j['a'].is_a?(String)
105
- return authenticate if j['a'] == false
106
- @authenticated = true if j['a'] == true
144
+ def receive_msg(m)
145
+ Kernel.puts "\033[1m! msg: " + m + "\033[0m"
146
+ end
107
147
 
108
- else
109
- warn "[pry-remote-em] received unexpected data: #{j.inspect}"
148
+ def receive_msg_bcast(mb)
149
+ Kernel.puts "\033[1m!! msg: " + mb + "\033[0m"
150
+ end
151
+
152
+ def receive_shell_cmd(c)
153
+ Kernel.puts c
154
+ end
155
+
156
+ def receive_shell_result(c)
157
+ if @keyboard
158
+ @keyboard.bufferio(true)
159
+ @keyboard.close_connection
110
160
  end
111
161
  end
112
162
 
163
+ def receive_raw(r)
164
+ # Pry::Helpers::BaseHelpers
165
+ stagger_output(r, $stdout)
166
+ end
167
+
168
+ def receive_unknown(j)
169
+ warn "[pry-remote-em] received unexpected data: #{j.inspect}"
170
+ end
171
+
113
172
  def authenticate
114
173
  return fail("[pry-remote-em] authentication required") unless @auth
115
174
  return fail("[pry-remote-em] can't authenticate before negotiation complete") unless @negotiated
116
175
  user, pass = @auth.call
117
176
  return fail("[pry-remote-em] expected #{@auth} to return a user and password") unless user && pass
118
- send_data({:a => [user, pass]})
177
+ send_auth([user, pass])
119
178
  end # authenticate
120
179
 
121
- def ssl_handshake_completed
122
- Kernel.puts "[pry-remote-em] TLS connection established"
180
+ def auto_complete(word)
181
+ @waiting = Thread.current
182
+ EM.next_tick { send_completion(word) }
183
+ sleep
184
+ c = Thread.current[:completion]
185
+ Thread.current[:completion] = nil
186
+ c
123
187
  end
124
188
 
125
- def start_tls
126
- Kernel.puts "[pry-remote-em] negotiating TLS"
127
- super(@opts[:tls].is_a?(Hash) ? @opts[:tls] : {})
189
+ def receive_completion(c)
190
+ return unless @waiting
191
+ @waiting[:completion] = c
192
+ @waiting, t = nil, @waiting
193
+ t.run
128
194
  end
129
195
 
130
- def unbind
131
- @unbound = true
132
- Kernel.puts "[pry-remote-em] session terminated"
133
- # prior to 1.0.0.b4 error? returns true here even when it's not
134
- return succeed if Gem.loaded_specs["eventmachine"].version < Gem::Version.new("1.0.0.beta4")
135
- error? ? fail : succeed
196
+ def receive_prompt(p)
197
+ readline(p)
136
198
  end
137
199
 
138
200
  def readline(prompt)
139
201
  if @negotiated && !@unbound
140
- Fiber.new {
141
- l = Readline.readline(prompt, !prompt.nil?)
202
+ op = proc { Readline.readline(prompt, !prompt.nil?) }
203
+ callback = proc do |l|
142
204
  if '!!' == l[0..1]
143
- send_data({:b => l[2..-1]})
205
+ send_msg_bcast(l[2..-1])
144
206
  elsif '!' == l[0]
145
- send_data({:m => l[1..-1]})
207
+ send_msg(l[1..-1])
146
208
  elsif '.' == l[0]
147
- send_data({:s => l[1..-1]})
148
- if Gem.loaded_specs["eventmachine"].version < Gem::Version.new("1.0.0.beta4")
149
- Kernel.puts "\033[1minteractive shell commands are not well supported when running on EventMachine prior 1.0.0.beta4\033[0m"
209
+ if !Client.const_defined?(:Keyboard)
210
+ Kernel.puts "\033[31minteractive shell commands are not supported without termios\033[0m"
211
+ readline(prompt)
150
212
  else
151
- @keyboard = EM.open_keyboard(Keyboard, self)
213
+ send_shell_cmd(l[1..-1])
214
+ if Gem.loaded_specs["eventmachine"].version < Gem::Version.new("1.0.0.beta4")
215
+ Kernel.puts "\033[1minteractive shell commands are not well supported when running on EventMachine prior to 1.0.0.beta4\033[0m"
216
+ else
217
+ @keyboard = EM.open_keyboard(Keyboard, self)
218
+ end
152
219
  end
153
220
  elsif 'reset' == l.strip
154
221
  # TODO work with 'bundle exec pry-remote-em ...'
@@ -156,9 +223,10 @@ module PryRemoteEm
156
223
  Kernel.puts "\033[1m#{$0} #{ARGV.join(' ')}\033[0m"
157
224
  exec("#{$0} #{ARGV.join(' ')}")
158
225
  else
159
- send_data(l)
226
+ send_raw(l)
160
227
  end # "!!" == l[0..1]
161
- }.resume
228
+ end
229
+ EM.defer(op, callback)
162
230
  end
163
231
  end # readline(prompt = @last_prompt)
164
232