pry-remote-em 1.1.0-java
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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +150 -0
- data/README.md +920 -0
- data/bin/pry-remote-em +89 -0
- data/bin/pry-remote-em-broker +28 -0
- data/lib/pry-remote-em.rb +74 -0
- data/lib/pry-remote-em/broker.rb +229 -0
- data/lib/pry-remote-em/client.rb +233 -0
- data/lib/pry-remote-em/client/broker.rb +39 -0
- data/lib/pry-remote-em/client/generic.rb +74 -0
- data/lib/pry-remote-em/client/interactive_menu.rb +193 -0
- data/lib/pry-remote-em/client/keyboard.rb +42 -0
- data/lib/pry-remote-em/client/proxy.rb +33 -0
- data/lib/pry-remote-em/metrics.rb +39 -0
- data/lib/pry-remote-em/proto.rb +148 -0
- data/lib/pry-remote-em/sandbox.rb +88 -0
- data/lib/pry-remote-em/server.rb +511 -0
- data/lib/pry-remote-em/server/shell_cmd.rb +20 -0
- data/lib/pry-remote-em/version.rb +3 -0
- metadata +121 -0
data/bin/pry-remote-em
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'uri'
|
4
|
+
require 'readline'
|
5
|
+
require 'highline'
|
6
|
+
require 'pry-remote-em/client'
|
7
|
+
require 'optparse'
|
8
|
+
|
9
|
+
options = {}
|
10
|
+
OptionParser.new do |opts|
|
11
|
+
opts.on('-c', '--connect NAME', 'connect to the first pry remote em server matching NAME') do |name|
|
12
|
+
options[:connect] = name
|
13
|
+
end
|
14
|
+
opts.on('-p', '--proxy NAME', 'proxy through the broker to the first pry remote em server matching NAME') do |name|
|
15
|
+
options[:proxy] = name
|
16
|
+
end
|
17
|
+
opts.on('-P', '--proxy-by-default', 'show servers table with proxy mode enabled by default (ignored on -c or -p)') do |name|
|
18
|
+
options[:proxy_by_default] = true
|
19
|
+
end
|
20
|
+
|
21
|
+
opts.on('--fh HOST', '--filter-host HOST', 'only show servers listening at the given address (regexp)') do |host|
|
22
|
+
if host =~ /^pryems?:\/\//
|
23
|
+
ARGV.push(host)
|
24
|
+
else
|
25
|
+
options[:filter_host] = Regexp.new(host)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
opts.on('--fn NAME', '--filter-name NAME', 'only show servers with a matching name (regexp)') do |name|
|
29
|
+
if name =~ /^pryems?:\/\//
|
30
|
+
ARGV.push(name)
|
31
|
+
else
|
32
|
+
options[:filter_name] = Regexp.new(name)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
opts.on('--[no-]fs', '--[no-]filter-ssl', 'show only servers that support ssl') do |ssl|
|
36
|
+
options[:filter_ssl] = ssl
|
37
|
+
end
|
38
|
+
|
39
|
+
opts.on('--sh', '--sort-host', 'sort by host') { options[:sort] = :host }
|
40
|
+
opts.on('--sn', '--sort-name', 'sort by server name') { |name| options[:sort] = :name }
|
41
|
+
opts.on('--sp', '--sort-port', 'sort by port') { options[:sort] = :port }
|
42
|
+
opts.on('--ss', '--sort-ssl', 'sort by ssl support') { options[:sort] = :ssl }
|
43
|
+
|
44
|
+
opts.on('-d', '--details KEY', "show value from server's details option by given key instead of url in table, use @ to show all details") do |key|
|
45
|
+
options[:show_details] = key
|
46
|
+
end
|
47
|
+
|
48
|
+
opts.on('-m', '--metrics KEY', "show value from server's metrics by given key in a third column, use @ to show all metrics, default - errors (if any)") do |key|
|
49
|
+
options[:show_metrics] = key
|
50
|
+
end
|
51
|
+
|
52
|
+
opts.on('-i', '--ignore-localhost', 'filter out localhost urls from list') do
|
53
|
+
options[:ignore_localhost] = true
|
54
|
+
end
|
55
|
+
|
56
|
+
opts.parse!(ARGV)
|
57
|
+
end
|
58
|
+
|
59
|
+
uri = if ARGV[0].nil? || ARGV[0].empty?
|
60
|
+
host = ENV['PRYEMBROKER'].nil? || ENV['PRYEMBROKER'].empty? ? PryRemoteEm::DEFAULT_BROKER_HOST : ENV['PRYEMBROKER']
|
61
|
+
port = ENV['PRYEMBROKERPORT'].nil? || ENV['PRYEMBROKERPORT'].empty? ? PryRemoteEm::DEFAULT_BROKER_PORT : ENV['PRYEMBROKERPORT']
|
62
|
+
"pryem://#{host}:#{port}"
|
63
|
+
else
|
64
|
+
ARGV[0]
|
65
|
+
end
|
66
|
+
uri = URI.parse(uri)
|
67
|
+
unless %w(pryem pryems).include?(uri.scheme)
|
68
|
+
abort "only pryem URIs are currently supported\n usage: pryem[s]://#{PryRemoteEm::DEFAULT_BROKER_HOST}:#{PryRemoteEm::DEFAULT_BROKER_PORT}"
|
69
|
+
end
|
70
|
+
uri.port = PryRemoteEm::DEFAULT_BROKER_PORT unless uri.port
|
71
|
+
|
72
|
+
tried = 0
|
73
|
+
auth_proc = proc do
|
74
|
+
tried += 1
|
75
|
+
user = uri.user || ($stdin.tty? ? Readline.readline('user: ') : raise('username is require for authentication'))
|
76
|
+
pass = if !uri.password.nil? && tried <= 1
|
77
|
+
uri.password
|
78
|
+
elsif $stdin.tty?
|
79
|
+
HighLine.new.ask("#{user}'s password: ") { |q| q.echo = '*' }
|
80
|
+
else
|
81
|
+
raise 'password is required to authenticate'
|
82
|
+
end
|
83
|
+
[user, pass]
|
84
|
+
end
|
85
|
+
|
86
|
+
EM.run do
|
87
|
+
client_options = options.merge(auth: auth_proc, tls: uri.scheme == 'pryems')
|
88
|
+
PryRemoteEm::Client.start(uri.host, uri.port, client_options) { EM.stop }
|
89
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'pry-remote-em/broker'
|
4
|
+
require 'optparse'
|
5
|
+
|
6
|
+
options = { tls: false }
|
7
|
+
OptionParser.new do |opts|
|
8
|
+
opts.on('-h', '--host HOST', 'host to bind broker server (same as PRYEMBROKER variable, default: "127.0.0.1")') do |host|
|
9
|
+
options[:host] = host
|
10
|
+
end
|
11
|
+
|
12
|
+
opts.on('-p', '--port PORT', 'port to bind broker server (same as PRYEMBROKERPORT variable, default: 6462)') do |port|
|
13
|
+
options[:port] = port
|
14
|
+
end
|
15
|
+
|
16
|
+
opts.on('-s', '--tls', 'use TLS for broker (default: false)') do
|
17
|
+
options[:tls] = true
|
18
|
+
end
|
19
|
+
|
20
|
+
opts.parse!(ARGV)
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
EM.run do
|
25
|
+
trap(:INT) { EM.stop }
|
26
|
+
|
27
|
+
PryRemoteEm::Broker.run options[:host], options[:port], tls: options[:tls], raise_if_port_in_use: true
|
28
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
begin
|
2
|
+
require 'openssl'
|
3
|
+
rescue LoadError
|
4
|
+
warn 'OpenSSL support is not available'
|
5
|
+
end
|
6
|
+
require 'socket'
|
7
|
+
require 'fiber'
|
8
|
+
require 'uri'
|
9
|
+
require 'eventmachine'
|
10
|
+
require 'pry-remote-em/version'
|
11
|
+
require 'pry-remote-em/proto'
|
12
|
+
require 'pry-remote-em/server'
|
13
|
+
|
14
|
+
module PryRemoteEm
|
15
|
+
DEFAULT_SERVER_HOST = '127.0.0.1'
|
16
|
+
DEFAULT_SERVER_PORT = 6463
|
17
|
+
DEFAULT_BROKER_HOST = '127.0.0.1'
|
18
|
+
DEFAULT_BROKER_PORT = 6462
|
19
|
+
|
20
|
+
NEGOTIATION_TIMEOUT = 15
|
21
|
+
HEARTBEAT_SEND_INTERVAL = 15
|
22
|
+
HEARTBEAT_CHECK_INTERVAL = 20
|
23
|
+
RECONNECT_TO_BROKER_TIMEOUT = 3
|
24
|
+
|
25
|
+
MAXIMUM_ERRORS_IN_SANDBOX = 100
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
class Object
|
30
|
+
def remote_pry_em(host = nil, port = nil, options = {}, &block)
|
31
|
+
host, options = nil, host if host.kind_of?(Hash) # Support for options hash as first argument instead of third
|
32
|
+
|
33
|
+
options = { target: self, host: host, port: port }.merge(options)
|
34
|
+
PryRemoteEm::Server.run(options, &block)
|
35
|
+
end
|
36
|
+
|
37
|
+
alias pry_remote_em remote_pry_em # source of common confusing
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
unless defined?(EventMachine.popen3)
|
42
|
+
module EventMachine
|
43
|
+
# @see http://eventmachine.rubyforge.org/EventMachine.html#M000491
|
44
|
+
# @see https://gist.github.com/535644/4d5b645b96764e07ccb53539529bea9270741e1a
|
45
|
+
def self.popen3(cmd, handler=nil, *args)
|
46
|
+
klass = klass_from_handler(Connection, handler, *args)
|
47
|
+
w = Shellwords::shellwords(cmd)
|
48
|
+
w.unshift(w.first) if w.first
|
49
|
+
|
50
|
+
new_stderr = $stderr.dup
|
51
|
+
rd, wr = IO::pipe
|
52
|
+
|
53
|
+
$stderr.reopen wr
|
54
|
+
s = invoke_popen(w)
|
55
|
+
$stderr.reopen new_stderr
|
56
|
+
|
57
|
+
klass.new(s, *args).tap do |c|
|
58
|
+
EM.attach(rd, Popen3StderrHandler, c)
|
59
|
+
@conns[s] = c
|
60
|
+
yield(c) if block_given?
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class Popen3StderrHandler < EventMachine::Connection
|
65
|
+
def initialize(connection)
|
66
|
+
@connection = connection
|
67
|
+
end
|
68
|
+
|
69
|
+
def receive_data(data)
|
70
|
+
@connection.receive_stderr(data)
|
71
|
+
end
|
72
|
+
end # class::Popen3StderrHandler
|
73
|
+
end # module::EventMachine
|
74
|
+
end # defined?(EventMachine.popen3)
|
@@ -0,0 +1,229 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'socket'
|
3
|
+
require 'pry-remote-em'
|
4
|
+
require 'pry-remote-em/client/broker'
|
5
|
+
require 'pry-remote-em/client/proxy'
|
6
|
+
|
7
|
+
module PryRemoteEm
|
8
|
+
module Broker
|
9
|
+
class << self
|
10
|
+
attr_reader :listening, :host, :port
|
11
|
+
alias :listening? :listening
|
12
|
+
|
13
|
+
def run(host = nil, port = nil, opts = {})
|
14
|
+
host ||= ENV['PRYEMBROKER'].nil? || ENV['PRYEMBROKER'].empty? ? DEFAULT_BROKER_HOST : ENV['PRYEMBROKER']
|
15
|
+
port ||= ENV['PRYEMBROKERPORT'].nil? || ENV['PRYEMBROKERPORT'].empty? ? DEFAULT_BROKER_PORT : ENV['PRYEMBROKERPORT']
|
16
|
+
port = port.to_i if port.kind_of?(String)
|
17
|
+
raise "root permission required for port below 1024 (#{port})" if port < 1024 && Process.euid != 0
|
18
|
+
@host = host
|
19
|
+
@port = port
|
20
|
+
opts = opts.dup
|
21
|
+
# Brokers cannot use SSL directly. If they do then when a proxy request to an SSL server is received
|
22
|
+
# the client and server will not be able to negotiate a SSL session. The proxied traffic can be SSL
|
23
|
+
# encrypted, but the SSL session will be between the client and the server.
|
24
|
+
opts[:tls] = false
|
25
|
+
@opts = opts
|
26
|
+
start_server(host, port, opts) unless @listening || ENV['PRYEMREMOTEBROKER'] || @opts[:remote_broker]
|
27
|
+
client { |c| yield self } if block_given?
|
28
|
+
end
|
29
|
+
|
30
|
+
def restart
|
31
|
+
log.info("[pry-remote-em broker] restarting on pryem://#{host}:#{port}")
|
32
|
+
@waiting = nil
|
33
|
+
@client = nil
|
34
|
+
run(@host, @port, @opts) do
|
35
|
+
PryRemoteEm.servers.each do |id, description|
|
36
|
+
next unless EM.get_sockname(description[:server])
|
37
|
+
register(
|
38
|
+
id: description[:id],
|
39
|
+
urls: description[:urls],
|
40
|
+
name: description[:name],
|
41
|
+
details: description[:details],
|
42
|
+
metrics: PryRemoteEm::Metrics.list
|
43
|
+
)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def opts
|
49
|
+
@opts ||= {}
|
50
|
+
end
|
51
|
+
|
52
|
+
def log
|
53
|
+
return opts[:logger] if opts[:logger]
|
54
|
+
@log ||= Logger.new(STDERR)
|
55
|
+
end
|
56
|
+
|
57
|
+
def servers
|
58
|
+
@servers ||= {}
|
59
|
+
end
|
60
|
+
|
61
|
+
def register(description)
|
62
|
+
client { |c| c.send_register_server(description[:id], description[:urls], description[:name], description[:details], description[:metrics]) }
|
63
|
+
end
|
64
|
+
|
65
|
+
def unregister(id)
|
66
|
+
client { |c| c.send_unregister_server(id) }
|
67
|
+
end
|
68
|
+
|
69
|
+
def register_server(id, description)
|
70
|
+
servers[id] = description
|
71
|
+
watch_heartbeats(id)
|
72
|
+
log.info("[pry-remote-em broker] registered #{id} #{description.inspect}")
|
73
|
+
end
|
74
|
+
|
75
|
+
def update_server(server, description)
|
76
|
+
server.update(urls: description[:urls], name: description[:name])
|
77
|
+
server[:details].update(description[:details])
|
78
|
+
server[:metrics].update(description[:metrics])
|
79
|
+
end
|
80
|
+
|
81
|
+
def unregister_server(id)
|
82
|
+
server = servers.delete(id) or return
|
83
|
+
log.warn("[pry-remote-em broker] unregister #{id} #{server.inspect}")
|
84
|
+
timer = timers.delete(id)
|
85
|
+
timer.cancel if timer
|
86
|
+
hbeats.delete(id)
|
87
|
+
end
|
88
|
+
|
89
|
+
def watch_heartbeats(id)
|
90
|
+
interval = ENV['PRYEMHBCHECK'].nil? || ENV['PRYEMHBCHECK'].empty? ? HEARTBEAT_CHECK_INTERVAL : ENV['PRYEMHBCHECK']
|
91
|
+
timers[id] ||= EM::PeriodicTimer.new(interval) do
|
92
|
+
if !hbeats[id] || (Time.new - hbeats[id]) > 20
|
93
|
+
unregister_server(id)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def timers
|
99
|
+
@timers ||= {}
|
100
|
+
end
|
101
|
+
|
102
|
+
def hbeats
|
103
|
+
@hbeats ||= {}
|
104
|
+
end
|
105
|
+
|
106
|
+
def connected?
|
107
|
+
@connected
|
108
|
+
end
|
109
|
+
|
110
|
+
private
|
111
|
+
|
112
|
+
def start_server(host, port, opts)
|
113
|
+
EM.start_server(host, port, PryRemoteEm::Broker, opts)
|
114
|
+
log.info("[pry-remote-em broker] listening on #{opts[:tls] ? 'pryems' : 'pryem'}://#{host}:#{port}")
|
115
|
+
@listening = true
|
116
|
+
rescue => error
|
117
|
+
if error.message.include?('port is in use')
|
118
|
+
if opts[:raise_if_port_in_use]
|
119
|
+
raise
|
120
|
+
else
|
121
|
+
# A broker is already listening on this port, we can do nothing
|
122
|
+
end
|
123
|
+
else
|
124
|
+
raise
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def client(&blk)
|
129
|
+
raise ArgumentError.new('A block is required') unless block_given?
|
130
|
+
if @client
|
131
|
+
yield @client
|
132
|
+
return
|
133
|
+
end
|
134
|
+
|
135
|
+
if @waiting
|
136
|
+
@waiting << blk
|
137
|
+
else
|
138
|
+
@waiting = [blk]
|
139
|
+
EM.connect(host, port, Client::Broker, @opts) do |client|
|
140
|
+
client.errback { |e| raise(e || 'broker client error') }
|
141
|
+
client.callback do
|
142
|
+
@client = client
|
143
|
+
while (w = @waiting.shift)
|
144
|
+
w.call(client)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end # class << self
|
151
|
+
|
152
|
+
include Proto
|
153
|
+
|
154
|
+
def receive_server_reload_list
|
155
|
+
send_server_list(Broker.servers)
|
156
|
+
end
|
157
|
+
|
158
|
+
def receive_register_server(id, urls, name, details, metrics)
|
159
|
+
@ids.push(id)
|
160
|
+
description = { urls: urls, name: name, details: details, metrics: metrics }
|
161
|
+
Broker.hbeats[id] = Time.new
|
162
|
+
server = Broker.servers[id]
|
163
|
+
if server
|
164
|
+
Broker.update_server(server, description)
|
165
|
+
else
|
166
|
+
Broker.register_server(id, description)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def receive_unregister_server(id)
|
171
|
+
server = Broker.servers[id]
|
172
|
+
Broker.unregister_server(id) if server
|
173
|
+
end
|
174
|
+
|
175
|
+
def receive_proxy_connection(url)
|
176
|
+
log.info("[pry-remote-em broker] proxying to #{url}")
|
177
|
+
url = URI.parse(url)
|
178
|
+
EM.connect(url.host, url.port, Client::Proxy, self)
|
179
|
+
end
|
180
|
+
|
181
|
+
def initialize(opts = {}, &blk)
|
182
|
+
@opts = opts
|
183
|
+
@ids = []
|
184
|
+
end
|
185
|
+
|
186
|
+
def log
|
187
|
+
Broker.log
|
188
|
+
end
|
189
|
+
|
190
|
+
def post_init
|
191
|
+
port, ip = Socket.unpack_sockaddr_in(get_peername)
|
192
|
+
log.info("[pry-remote-em broker] received client connection from #{ip}:#{port}")
|
193
|
+
send_banner("PryRemoteEm #{VERSION} #{@opts[:tls] ? 'pryems' : 'pryem'}")
|
194
|
+
@opts[:tls] ? start_tls : send_server_list(Broker.servers)
|
195
|
+
end
|
196
|
+
|
197
|
+
def start_tls
|
198
|
+
log.debug("[pry-remote-em broker] starting TLS (#{peer_ip}:#{peer_port})")
|
199
|
+
send_start_tls
|
200
|
+
super(@opts[:tls].is_a?(Hash) ? @opts[:tls] : {})
|
201
|
+
end
|
202
|
+
|
203
|
+
def peer_ip
|
204
|
+
return @peer_ip if @peer_ip
|
205
|
+
return '' if get_peername.nil?
|
206
|
+
@peer_port, @peer_ip = Socket.unpack_sockaddr_in(get_peername)
|
207
|
+
@peer_ip = '127.0.0.1' if @peer_ip == '::1' # Little hack to avoid segmentation fault in EventMachine 1.2.0.1 while connecting to PryRemoteEm Server from localhost with IPv6 address
|
208
|
+
@peer_ip
|
209
|
+
end
|
210
|
+
|
211
|
+
def peer_port
|
212
|
+
return @peer_port if @peer_port
|
213
|
+
return '' if get_peername.nil?
|
214
|
+
peer_ip # Fills peer_port too
|
215
|
+
@peer_port
|
216
|
+
end
|
217
|
+
|
218
|
+
def ssl_handshake_completed
|
219
|
+
log.info("[pry-remote-em broker] TLS connection established (#{peer_ip}:#{peer_port})")
|
220
|
+
send_server_list(Broker.servers)
|
221
|
+
end
|
222
|
+
|
223
|
+
def unbind
|
224
|
+
@ids.each do |id|
|
225
|
+
Broker.unregister_server(id)
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end # module::Broker
|
229
|
+
end # module::PryRemoteEm
|
@@ -0,0 +1,233 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'pry-remote-em'
|
3
|
+
require 'pry-remote-em/client/keyboard'
|
4
|
+
require 'pry-remote-em/client/generic'
|
5
|
+
require 'pry-remote-em/client/interactive_menu'
|
6
|
+
require 'pry'
|
7
|
+
#require 'pry-coolline' rescue require 'readline'
|
8
|
+
|
9
|
+
module PryRemoteEm
|
10
|
+
module Client
|
11
|
+
include EM::Deferrable
|
12
|
+
include Generic
|
13
|
+
include InteractiveMenu
|
14
|
+
include Pry::Helpers::BaseHelpers
|
15
|
+
|
16
|
+
class << self
|
17
|
+
def start(host = nil, port = nil, opts = {})
|
18
|
+
EM.connect(host || PryRemoteEm::DEFAULT_SERVER_HOST, port || PryRemoteEm::DEFAULT_SERVER_PORT, PryRemoteEm::Client, opts) do |c|
|
19
|
+
c.callback { yield if block_given? }
|
20
|
+
c.errback do |e|
|
21
|
+
Kernel.puts "[pry-remote-em] connection failed\n#{e}"
|
22
|
+
yield(e) if block_given?
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end # class << self
|
27
|
+
|
28
|
+
attr_reader :opts
|
29
|
+
|
30
|
+
def initialize(opts = {})
|
31
|
+
@opts = opts
|
32
|
+
if (a = opts[:auth])
|
33
|
+
if a.respond_to?(:call)
|
34
|
+
@auth = a
|
35
|
+
else
|
36
|
+
@auth = lambda { a }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def post_init
|
42
|
+
@input = if defined?(PryCoolline)
|
43
|
+
PryCoolline.make_coolline
|
44
|
+
else
|
45
|
+
Pry.history.load if Pry.config.history.should_load
|
46
|
+
Readline
|
47
|
+
end
|
48
|
+
@input.completion_proc = method(:auto_complete)
|
49
|
+
end
|
50
|
+
|
51
|
+
def ssl_handshake_completed
|
52
|
+
log.info('[pry-remote-em] TLS connection established')
|
53
|
+
@opts[:tls] = true
|
54
|
+
end
|
55
|
+
|
56
|
+
def unbind
|
57
|
+
if (uri = @reconnect_to)
|
58
|
+
@reconnect_to = nil
|
59
|
+
tls = uri.scheme == 'pryems'
|
60
|
+
log.info("\033[35m[pry-remote-em] connection will not be encrypted\033[0m") if @opts[:tls] && !tls
|
61
|
+
@opts[:tls] = tls
|
62
|
+
@tls_started = false
|
63
|
+
reconnect(uri.host, uri.port)
|
64
|
+
else
|
65
|
+
@unbound = true
|
66
|
+
log.info('[pry-remote-em] session terminated')
|
67
|
+
error? ? fail : succeed
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def receive_banner(name, version, scheme)
|
72
|
+
# Client::Generic#receive_banner
|
73
|
+
if super(name, version, scheme)
|
74
|
+
start_tls if @opts[:tls]
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def receive_server_list(list)
|
79
|
+
if list.empty?
|
80
|
+
log.info("\033[33m[pry-remote-em] no servers are registered with the broker\033[0m")
|
81
|
+
Process.exit
|
82
|
+
end
|
83
|
+
url, proxy = choose_server(list)
|
84
|
+
return unless url
|
85
|
+
uri = URI.parse(url)
|
86
|
+
if proxy
|
87
|
+
@opts[:tls] = uri.scheme == 'pryems'
|
88
|
+
@negotiated = false
|
89
|
+
@tls_started = false
|
90
|
+
return send_proxy_connection(url)
|
91
|
+
end
|
92
|
+
@reconnect_to = uri
|
93
|
+
close_connection
|
94
|
+
end
|
95
|
+
|
96
|
+
def receive_auth(a)
|
97
|
+
return fail a if a.is_a?(String)
|
98
|
+
return authenticate if a == false
|
99
|
+
@authenticated = true if a == true
|
100
|
+
end
|
101
|
+
|
102
|
+
def receive_msg(m)
|
103
|
+
Kernel.puts "\033[1m! msg: " + m + "\033[0m"
|
104
|
+
end
|
105
|
+
|
106
|
+
def receive_msg_bcast(mb)
|
107
|
+
Kernel.puts "\033[1m!! msg: " + mb + "\033[0m"
|
108
|
+
end
|
109
|
+
|
110
|
+
def receive_shell_cmd(c)
|
111
|
+
Kernel.puts c
|
112
|
+
end
|
113
|
+
|
114
|
+
def receive_shell_result(c)
|
115
|
+
if @keyboard
|
116
|
+
@keyboard.bufferio(true)
|
117
|
+
@keyboard.close_connection
|
118
|
+
end
|
119
|
+
if c == 255 || c == 127
|
120
|
+
Kernel.puts 'command not found'
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# TODO detect if the old pager behavior of Pry is supported and use it
|
125
|
+
# through Pry.pager. If it's not then use the SimplePager.
|
126
|
+
def pager
|
127
|
+
pager_class = ENV['PRYEMNOPAGER'] ? Pry::Pager::NullPager : @opts[:pager] || Pry::Pager::SimplePager
|
128
|
+
@pager ||= pager_class.new(Pry::Output.new(Pry))
|
129
|
+
end
|
130
|
+
|
131
|
+
def receive_raw(r)
|
132
|
+
pager.write(r)
|
133
|
+
rescue Pry::Pager::StopPaging
|
134
|
+
warn '[pry-remote-em] stop paging is not implemented, use PRYEMNOPAGER environment variable to avoid paging at all'
|
135
|
+
end
|
136
|
+
|
137
|
+
def receive_unknown(j)
|
138
|
+
warn "[pry-remote-em] received unexpected data: #{j.inspect}"
|
139
|
+
end
|
140
|
+
|
141
|
+
def authenticate
|
142
|
+
return fail('[pry-remote-em] authentication required') unless @auth
|
143
|
+
return fail("[pry-remote-em] can't authenticate before negotiation complete") unless @negotiated
|
144
|
+
user, pass = @auth.call
|
145
|
+
return fail("[pry-remote-em] expected #{@auth} to return a user and password") unless user && pass
|
146
|
+
send_auth([user, pass])
|
147
|
+
end # authenticate
|
148
|
+
|
149
|
+
def auto_complete(word)
|
150
|
+
word = word.completed_word if defined?(Coolline) && word.kind_of?(Coolline)
|
151
|
+
|
152
|
+
@waiting = Thread.current
|
153
|
+
EM.next_tick { send_completion(word) }
|
154
|
+
sleep
|
155
|
+
c = Thread.current[:completion]
|
156
|
+
Thread.current[:completion] = nil
|
157
|
+
c
|
158
|
+
end
|
159
|
+
|
160
|
+
def receive_completion(c)
|
161
|
+
return unless @waiting
|
162
|
+
@waiting[:completion] = c
|
163
|
+
@waiting, t = nil, @waiting
|
164
|
+
t.run
|
165
|
+
end
|
166
|
+
|
167
|
+
def receive_prompt(p)
|
168
|
+
readline(p)
|
169
|
+
end
|
170
|
+
|
171
|
+
def readline(prompt = @last_prompt)
|
172
|
+
@last_prompt = prompt
|
173
|
+
if @negotiated && !@unbound
|
174
|
+
operation = proc do
|
175
|
+
thread = Thread.current
|
176
|
+
old_trap = Signal.trap(:INT) { thread.raise Interrupt }
|
177
|
+
begin
|
178
|
+
@input.readline(prompt)
|
179
|
+
rescue Interrupt
|
180
|
+
send_clear_buffer
|
181
|
+
puts
|
182
|
+
:ignore_me
|
183
|
+
ensure
|
184
|
+
Signal.trap(:INT, old_trap)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
callback = proc do |l|
|
189
|
+
next if l == :ignore_me
|
190
|
+
|
191
|
+
add_to_history(l) unless l.nil? || l.empty?
|
192
|
+
|
193
|
+
if l.nil?
|
194
|
+
readline
|
195
|
+
elsif '^^' == l[0..1]
|
196
|
+
send_msg_bcast(l[2..-1])
|
197
|
+
elsif '^' == l[0]
|
198
|
+
send_msg(l[1..-1])
|
199
|
+
elsif '.' == l[0]
|
200
|
+
send_shell_cmd(l[1..-1])
|
201
|
+
@keyboard = EM.open_keyboard(Keyboard, self)
|
202
|
+
elsif 'reset' == l.strip
|
203
|
+
# TODO work with 'bundle exec pry-remote-em ...'
|
204
|
+
# TODO work with 'ruby -I lib bin/pry-remote-em ...'
|
205
|
+
Kernel.puts "\033[1m#{$0} #{ARGV.join(' ')}\033[0m"
|
206
|
+
exec("#{$0} #{ARGV.join(' ')}")
|
207
|
+
else
|
208
|
+
send_raw(l)
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
EM.defer(operation, callback)
|
213
|
+
end
|
214
|
+
end # readline(prompt = @last_prompt)
|
215
|
+
|
216
|
+
def add_to_history(line)
|
217
|
+
if defined?(Readline) && @input == Readline
|
218
|
+
Readline::HISTORY.push(line)
|
219
|
+
end
|
220
|
+
# Nothing to do with Coolline, it just works
|
221
|
+
end
|
222
|
+
end # module::Client
|
223
|
+
end # module::PryRemoteEm
|
224
|
+
|
225
|
+
# TODO detect if the old pager behavior of Pry is supported and use it. If it's not
|
226
|
+
# then don't bother adding a pager accessor
|
227
|
+
# Pry::Helpers::BaseHelpers#stagger_output expects Pry.pager to be defined
|
228
|
+
class Pry
|
229
|
+
class << self
|
230
|
+
attr_accessor :pager unless respond_to?(:pager)
|
231
|
+
end
|
232
|
+
end
|
233
|
+
Pry.pager = true
|