pry-remote-em 1.1.0-java
Sign up to get free protection for your applications and to get access to all the features.
- 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
|