pry-remote-em 0.6.3 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,36 @@
1
+ require "pry-remote-em/client/generic"
2
+
3
+ module PryRemoteEm
4
+ module Client
5
+ module Broker
6
+ include Client::Generic
7
+ include EM::Deferrable
8
+
9
+ def log
10
+ return opts[:logger] if opts[:logger]
11
+ @log ||= Logger.new(STDERR)
12
+ end
13
+
14
+ def receive_banner(name, version, scheme)
15
+ if super(name, version, scheme)
16
+ @opts[:tls] ? start_tls : succeed(self)
17
+ end
18
+ end
19
+
20
+ def ssl_handshake_completed
21
+ succeed(self)
22
+ end
23
+
24
+ def unbind
25
+ log.info("[pry-remote-em broker-client] broker connection unbound starting a new one")
26
+ # Give the existing broker a little time to release the port. Even if the
27
+ # restart here fails the next time a server tries to register, a new client
28
+ # will be created; when that fails Broker#restart will be called again.
29
+ EM::Timer.new(rand(0.9)) do
30
+ PryRemoteEm::Broker.restart
31
+ end
32
+ end
33
+
34
+ end # module::Broker
35
+ end # module::Client
36
+ end # module::PryRemoteEm
@@ -0,0 +1,73 @@
1
+ require "pry-remote-em/proto"
2
+
3
+ module PryRemoteEm
4
+ module Client
5
+ module Generic
6
+ include EM::Deferrable
7
+ include Proto
8
+
9
+ def initialize(opt = {})
10
+ @opts = opts
11
+ end
12
+
13
+ def opts
14
+ @opts ||= {}
15
+ end
16
+
17
+ def log
18
+ @log ||= Class.new do
19
+ def print(str); $stderr.puts(str) end
20
+ alias :info :print
21
+ alias :warn :print
22
+ alias :error :print
23
+ alias :debug :print
24
+ end.new
25
+ end
26
+
27
+ def start_tls
28
+ return if @tls_started
29
+ @tls_started = true
30
+ log.info("[pry-remote-em] negotiating TLS")
31
+ super(opts[:tls].is_a?(Hash) ? opts[:tls] : {})
32
+ end
33
+
34
+ def connection_completed
35
+ if get_peername
36
+ port, ip = Socket.unpack_sockaddr_in(get_peername)
37
+ log.info("[pry-remote-em] client connected to pryem://#{ip}:#{port}/")
38
+ else
39
+ # TODO use the args used to create this connection
40
+ log.info("[pry-remote-em] client connected")
41
+ end
42
+ @nego_timer = EM::Timer.new(PryRemoteEm::NEGOTIMER) do
43
+ fail("[pry-remote-em] server didn't finish negotiation within #{PryRemoteEm::NEGOTIMER} seconds; terminating")
44
+ end
45
+ end
46
+
47
+ def receive_banner(name, version, scheme)
48
+ log.info("[pry-remote-em] remote is #{name} #{version} #{scheme}")
49
+ client_ver = Gem::Version.new(PryRemoteEm::VERSION)
50
+ server_req = Gem::Requirement.new("~>#{version}")
51
+ server_ver = Gem::Version.new(version)
52
+ client_req = Gem::Requirement.new("~>#{PryRemoteEm::VERSION}")
53
+ unless server_req.satisfied_by?(client_ver) || client_req.satisfied_by?(server_ver)
54
+ fail("[pry-remote-em] incompatible version #{PryRemoteEm::VERSION}")
55
+ return false
56
+ end
57
+ if scheme.nil? || scheme != (reqscheme = opts[:tls] ? 'pryems' : 'pryem')
58
+ if scheme == 'pryems' && defined?(::OpenSSL)
59
+ opts[:tls] = true
60
+ else
61
+ fail("[pry-remote-em] server doesn't support required scheme #{reqscheme.dump}")
62
+ return false
63
+ end
64
+ end
65
+ @negotiated = true
66
+ @nego_timer.cancel
67
+ true
68
+ end
69
+
70
+
71
+ end # module::Generic
72
+ end # module::Client
73
+ end # module::PryRemoteEm
@@ -0,0 +1,32 @@
1
+ require "pry-remote-em/client/generic"
2
+ module PryRemoteEm
3
+ module Client
4
+ module Proxy
5
+
6
+ def initialize(client, opts = {})
7
+ @opts = opts
8
+ @client = client
9
+ end
10
+
11
+ def connection_completed
12
+ if get_peername
13
+ port, ip = Socket.unpack_sockaddr_in(get_peername)
14
+ log.info("[pry-remote-em] proxy connected to pryem://#{ip}:#{port}/")
15
+ else
16
+ log.info("[pry-remote-em] proxy connected")
17
+ end
18
+ @client.proxy_incoming_to(self)
19
+ proxy_incoming_to(@client)
20
+ end
21
+
22
+ def log
23
+ return @opts[:logger] if @opts[:logger]
24
+ @log ||= Logger.new(STDERR)
25
+ end
26
+
27
+ def unbind
28
+ @client && @client.close_connection(true)
29
+ end
30
+ end # module::Proxy
31
+ end # module::Client
32
+ end # module::PryRemoteEm
@@ -0,0 +1,167 @@
1
+ require 'json'
2
+ require "zlib"
3
+
4
+ module PryRemoteEm
5
+ module Proto
6
+ PREAMBLE = 'PRYEM'
7
+ SEPERATOR = ' '
8
+ PREAMBLE_LEN = PREAMBLE.length
9
+ SEPERATOR_LEN = SEPERATOR.length
10
+
11
+ def send_json(d)
12
+ send_data(JSON.dump(d.is_a?(String) ? {:d => d} : d))
13
+ end
14
+
15
+ def send_data(data)
16
+ crc = Zlib::crc32(data).to_s
17
+ msg = PREAMBLE + (data.length + crc.length + SEPERATOR_LEN).to_s + SEPERATOR + crc + SEPERATOR + data
18
+ super(msg)
19
+ end
20
+
21
+ # Each frame is a string consisting of 4 parts
22
+ # 1. preamble (PRYEM)
23
+ # 2. length in characters of crc, a seperator, and body
24
+ # 3. CRC
25
+ # 4. JSON encoded body
26
+ # It is possible and likely that receive_data will be given more than one frame at a time, or
27
+ # an incomplete frame.
28
+ # @example "PRYEM42 3900082256 {\"g\":\"PryRemoteEm 0.7.0 pryem\"}PRYEM22 1794245389 {\"a\":false}"
29
+ def receive_data(d)
30
+ return unless d && d.length > 0
31
+ @buffer ||= "" # inlieu of a post_init
32
+ @buffer << d
33
+ while @buffer && !@buffer.empty?
34
+ return unless @buffer.length >= PREAMBLE_LEN &&
35
+ (len_ends = @buffer.index(SEPERATOR)) &&
36
+ (crc_ends = @buffer.index(SEPERATOR, len_ends))
37
+ if (preamble = @buffer[0...PREAMBLE_LEN]) != PREAMBLE
38
+ raise "message is not in proper format; expected #{PREAMBLE.inspect} not #{preamble.inspect}"
39
+ end
40
+ length = @buffer[PREAMBLE_LEN ... len_ends].to_i
41
+ return if len_ends + length > @buffer.length
42
+ crc_start = len_ends + SEPERATOR_LEN
43
+ crc, data = @buffer[crc_start ... crc_start + length].split(SEPERATOR, 2)
44
+ crc = crc.to_i
45
+ @buffer = @buffer[crc_start + length .. -1]
46
+ if (dcrc = Zlib::crc32(data)) == crc
47
+ receive_json(JSON.load(data))
48
+ else
49
+ warn("data crc #{dcrc} doesn't match crc #{crc.inspect}; discarding #{data.inspect}")
50
+ end
51
+ end
52
+ @buffer
53
+ end
54
+
55
+ def receive_json(j)
56
+ if j['p']
57
+ receive_prompt(j['p'])
58
+ elsif j['d']
59
+ receive_raw(j['d'])
60
+ elsif j['m']
61
+ receive_msg(j['m'])
62
+ elsif j['mb']
63
+ receive_msg_bcast(j['mb'])
64
+ elsif j['s']
65
+ receive_shell_cmd(j['s'])
66
+ elsif j.include?('sc')
67
+ receive_shell_result(j['sc'])
68
+ elsif j['g']
69
+ receive_banner(*j['g'].split(" ", 3))
70
+ elsif j['c']
71
+ receive_completion(j['c'])
72
+ elsif j.include?('a')
73
+ receive_auth(*Array(j['a']))
74
+ elsif j['sd']
75
+ receive_shell_data(j['sd'])
76
+ elsif j['ssc']
77
+ receive_shell_sig(:term)
78
+ elsif j['hb']
79
+ receive_heartbeat(j['hb'])
80
+ elsif j['rs']
81
+ receive_register_server(*Array(j['rs']))
82
+ elsif j['urs']
83
+ receive_unregister_server(j['urs'])
84
+ elsif j.include?('sl')
85
+ j['sl'] ? receive_server_list(j['sl']) : receive_server_list
86
+ elsif j['tls']
87
+ receive_start_tls
88
+ elsif j['pc']
89
+ receive_proxy_connection(j['pc'])
90
+ else
91
+ receive_unknown(j)
92
+ end
93
+ j
94
+ end
95
+
96
+
97
+ def receive_prompt(p); end
98
+ def receive_banner(name, version, scheme); end
99
+ def receive_auth(a, b = nil); end
100
+ def receive_msg(m); end
101
+ def receive_msg_bcast(mb); end
102
+ def receive_shell_cmd(c); end
103
+ def receive_shell_result(c); end
104
+ def receive_completion(c); end
105
+ def receive_raw(r); end
106
+ def receive_shell_sig(sym); end
107
+ def receive_shell_data(d); end
108
+ def receive_unknown(j); end
109
+
110
+ def receive_start_tls; end
111
+
112
+ def receive_register_server(url, name); end
113
+ def receive_unregister_server(url); end
114
+ def receive_server_list(list = nil); end
115
+
116
+ def receive_proxy_connection(url); end
117
+
118
+ def send_banner(g)
119
+ send_json({:g => g})
120
+ end
121
+ def send_auth(a)
122
+ send_json({:a => a})
123
+ end
124
+ def send_prompt(p)
125
+ send_json({:p => p})
126
+ end
127
+ def send_msg_bcast(m)
128
+ send_json({:mb => m})
129
+ end
130
+ def send_msg(m)
131
+ send_json({:m => m})
132
+ end
133
+ def send_shell_cmd(c)
134
+ send_json({:s => c})
135
+ end
136
+ def send_shell_result(r)
137
+ send_json({:sc => r})
138
+ end
139
+ def send_completion(word)
140
+ send_json({:c => word})
141
+ end
142
+ def send_raw(l)
143
+ send_json(l)
144
+ end
145
+
146
+ def send_start_tls
147
+ send_json({:tls => true})
148
+ end
149
+
150
+ def send_register_server(url, name)
151
+ send_json({:rs => [url, name]})
152
+ end
153
+ def send_unregister_server(url)
154
+ send_json({:urs => url})
155
+ end
156
+ def send_heatbeat(url)
157
+ send_json({:hb => url})
158
+ end
159
+ def send_server_list(list = nil)
160
+ send_json({:sl => list})
161
+ end
162
+
163
+ def send_proxy_connection(url)
164
+ send_json({:pc => url})
165
+ end
166
+ end # module::Proto
167
+ end # module::PryRemoteEm
@@ -1,7 +1,9 @@
1
1
  require 'pry'
2
2
  require 'logger'
3
3
  require 'pry-remote-em'
4
+ require 'pry-remote-em/broker'
4
5
  require 'pry-remote-em/server/shell_cmd'
6
+
5
7
  # How it works with Pry
6
8
  #
7
9
  # When PryRemoteEm.run is called it registers with EventMachine for a given ip
@@ -26,14 +28,41 @@ require 'pry-remote-em/server/shell_cmd'
26
28
  # Pry just interacts with PryRemoteEm as if it were any other blocking Readline
27
29
  # object. The important bit is making sure that it is started in a new Fiber that
28
30
  # can be paused and resumed as needed. PryRemoteEm#readline pauses it and
29
- # PryRemoteEm#receive_json resumes it.
31
+ # PryRemoteEm#receive_raw resumes it.
30
32
  #
31
33
  # Reference:
32
34
  # http://www.igvita.com/2010/03/22/untangling-evented-code-with-ruby-fibers/
33
-
34
35
  module PryRemoteEm
36
+ class << self
37
+ # Local PryRemoteEm EM signatures and server name indexed by url. Each
38
+ # signature can be used with high level EM methods like EM.stop_server or
39
+ # EM.get_sockname. If a server has been stopped EM.get_sockname will return
40
+ # nil for that server's signature.
41
+ def servers
42
+ @servers ||= {}
43
+ end
44
+
45
+ # Safely stop one or more PryRemoteEm servers and remove them from the list
46
+ # of servers.
47
+ # @param [String] id url or name
48
+ def stop_server(id)
49
+ if servers[id]
50
+ EM.stop_server(servers[id][0]) if EM.get_sockname(servers[id][0])
51
+ Broker.unregister(id)
52
+ servers.delete(id)
53
+ return Array(id)
54
+ end
55
+ servers.select{ |i, (sig, name)| name == id }.map do |i, (sig, name)|
56
+ EM.stop_server(sig) if EM.get_sockname(sig)
57
+ Broker.unregister(i)
58
+ servers.delete(i)
59
+ i
60
+ end
61
+ end # stop_server(id)
62
+ end
63
+
35
64
  module Server
36
- include JsonProto
65
+ include Proto
37
66
 
38
67
  class << self
39
68
  # Start a pry-remote-em server
@@ -46,11 +75,12 @@ module PryRemoteEm
46
75
  # @option opts [Proc, Object] :auth require user authentication - see README
47
76
  # @option opts [Boolean] :allow_shell_cmds
48
77
  def run(obj, host = DEFHOST, port = DEFPORT, opts = {:tls => false})
49
- tries = :auto == port ? 100.tap{ port = DEFPORT } : 1
78
+ tries = [port, opts[:port_fail]].include?(:auto) ? 100 : 1
79
+ port = DEFPORT if :auto == port
50
80
  # TODO raise a useful exception not RuntimeError
51
81
  raise "root permission required for port below 1024 (#{port})" if port < 1024 && Process.euid != 0
52
82
  begin
53
- EM.start_server(host, port, PryRemoteEm::Server, obj, opts) do |pre|
83
+ server = EM.start_server(host, port, PryRemoteEm::Server, obj, opts) do |pre|
54
84
  Fiber.new {
55
85
  begin
56
86
  yield pre if block_given?
@@ -62,16 +92,29 @@ module PryRemoteEm
62
92
  end
63
93
  rescue => e
64
94
  # EM 1.0.0.beta4's message tells us the port is in use; 0.12.10 just says, 'no acceptor'
65
- if (e.message.include?('port is in use') || e.message.include?('no acceptor')) && tries >= 1
95
+ if (e.message.include?('port is in use') || e.message.include?('no acceptor')) && tries > 1
66
96
  tries -= 1
67
97
  port += 1
68
98
  retry
69
99
  end
70
- raise e
100
+ raise "can't bind to #{host}:#{port} - #{e}"
101
+ end
102
+ url = "#{opts[:tls] ? 'pryems' : 'pryem'}://#{host}:#{port}/"
103
+ begin
104
+ name = obj.send(:eval, 'self')
105
+ rescue
106
+ name = "#{obj}"
107
+ end
108
+ name = Pry.view_clip(name)
109
+ PryRemoteEm.servers[url] = [server, name]
110
+ (opts[:logger] || ::Logger.new(STDERR)).info("[pry-remote-em] listening for connections on #{url}")
111
+ Broker.run(opts[:broker_host] || ENV['PRYEMBROKER'] || DEF_BROKERHOST, opts[:broker_port] || ENV['PRYEMBROKERPORT'] || DEF_BROKERPORT, opts)
112
+ EM::Timer.new(rand(0.9)) { Broker.register(url, name) }
113
+ rereg = EM::PeriodicTimer.new(15) do
114
+ EM.get_sockname(server) ? Broker.register(url, name) : nil #rereg.cancel
71
115
  end
72
- scheme = opts[:tls] ? 'pryems' : 'pryem'
73
- (opts[:logger] || ::Logger.new(STDERR)).info("[pry-remote-em] listening for connections on #{scheme}://#{host}:#{port}/")
74
- end # run(obj, host = DEFHOST, port = DEFPORT)
116
+ url
117
+ end
75
118
 
76
119
  # The list of pry-remote-em connections for a given object, or the list of all pry-remote-em
77
120
  # connections for this process.
@@ -127,14 +170,21 @@ module PryRemoteEm
127
170
  end
128
171
  end
129
172
 
173
+ def url
174
+ port, host = Socket.unpack_sockaddr_in(get_sockname)
175
+ "#{@opts[:tls] ? 'pryems' : 'pryem'}://#{host}:#{port}/"
176
+ end
177
+
130
178
  def post_init
131
179
  @lines = []
132
180
  Pry.config.pager, @old_pager = false, Pry.config.pager
133
181
  @auth_required = @auth
134
182
  port, ip = Socket.unpack_sockaddr_in(get_peername)
135
183
  @log.info("[pry-remote-em] received client connection from #{ip}:#{port}")
136
- send_data({:g => "PryRemoteEm #{VERSION} #{@opts[:tls] ? 'pryems' : 'pryem'}"})
137
- @opts[:tls] ? start_tls : (@auth_required && send_data({:a => false}))
184
+ # TODO include first level prompt in banner
185
+ send_banner("PryRemoteEm #{VERSION} #{@opts[:tls] ? 'pryems' : 'pryem'}")
186
+ @log.info("#{url} PryRemoteEm #{VERSION} #{@opts[:tls] ? 'pryems' : 'pryem'}")
187
+ @opts[:tls] ? start_tls : (@auth_required && send_auth(false))
138
188
  PryRemoteEm::Server.register(@obj, self)
139
189
  end
140
190
 
@@ -145,7 +195,7 @@ module PryRemoteEm
145
195
 
146
196
  def ssl_handshake_completed
147
197
  @log.info("[pry-remote-em] TLS connection established (#{peer_ip}:#{peer_port})")
148
- send_data({:a => false}) if @auth_required
198
+ send_auth(false) if @auth_required
149
199
  end
150
200
 
151
201
  def peer_ip
@@ -162,74 +212,94 @@ module PryRemoteEm
162
212
  @peer_port
163
213
  end
164
214
 
165
- def receive_json(j)
166
- return send_data({:a => false}) if @auth_required && !j['a']
215
+ def receive_raw(d)
216
+ return if require_auth
217
+ return send_last_prompt if d.nil? || d.empty?
218
+ @lines.push(*d.split("\n"))
219
+ if @waiting
220
+ f, @waiting = @waiting, nil
221
+ f.resume(@lines.shift)
222
+ end
223
+ end
224
+
225
+ # tab completion request
226
+ def receive_completion(c)
227
+ return if require_auth
228
+ send_completion(@compl_proc.call(c))
229
+ end
167
230
 
168
- if j['d'] # just normal data
169
- return send_last_prompt if j['d'].empty?
170
- @lines.push(*j['d'].split("\n"))
171
- if @waiting
172
- f, @waiting = @waiting, nil
173
- f.resume(@lines.shift)
174
- end
175
- elsif j['c'] # tab completion request
176
- send_data({:c => @compl_proc.call(j['c'])})
177
-
178
- elsif j['a'] # authentication response
179
- return send_data({:a => true}) if !@auth || !@auth_required
180
- return send_data({:a => 'auth data must be a two element array'}) unless j['a'].is_a?(Array) && j['a'].length == 2
181
- auth_attempt(j['a'][0], peer_ip)
182
- unless (@auth_required = !@auth.call(*j['a']))
183
- @user = j['a'][0]
184
- auth_ok(j['a'][0], peer_ip)
185
- authenticated!
186
- else
187
- auth_fail(j['a'][0], peer_ip)
188
- if @auth_tries <= 0
189
- msg = "max authentication attempts reached"
190
- send_data({:a => msg})
191
- @log.debug("[pry-remote-em] #{msg} (#{peer_ip}:#{peer_port})")
192
- return close_connection_after_writing
193
- end
194
- @auth_tries -= 1
231
+ def receive_auth(user, pass)
232
+ return send_auth(true) if !@auth || !@auth_required
233
+ return send_auth('auth data must include a user and pass') if user.nil? || pass.nil?
234
+ auth_attempt(user, peer_ip)
235
+ unless (@auth_required = !@auth.call(user, pass))
236
+ @user = user
237
+ auth_ok(user, peer_ip)
238
+ authenticated!
239
+ else
240
+ auth_fail(user, peer_ip)
241
+ if @auth_tries <= 0
242
+ msg = "max authentication attempts reached"
243
+ send_auth(msg)
244
+ @log.debug("[pry-remote-em] #{msg} (#{peer_ip}:#{peer_port})")
245
+ return close_connection_after_writing
195
246
  end
196
- return send_data({:a => !@auth_required})
247
+ @auth_tries -= 1
248
+ end
249
+ return send_auth(!@auth_required)
250
+ end
197
251
 
198
- elsif j['m'] # message all peer connections
199
- peers.each { |peer| peer.send_message(j['m'], @user) }
200
- send_last_prompt
252
+ def receive_msg(m)
253
+ return if require_auth
254
+ peers.each { |peer| peer.send_message(m, @user) }
255
+ send_last_prompt
256
+ end
201
257
 
202
- elsif j['b'] # broadcast message
203
- peers(:all).each { |peer| peer.send_bmessage(j['b'], @user) }
204
- send_last_prompt
258
+ def receive_msg_bcast(mb)
259
+ return if require_auth
260
+ peers(:all).each { |peer| peer.send_bmessage(mb, @user) }
261
+ send_last_prompt
262
+ end
205
263
 
206
- elsif j['s'] # shell command
207
- # TODO confirm shell command's are allowed
208
- unless @allow_shell_cmds
209
- puts "\033[1mshell commands are not allowed by this server\033[0m"
210
- @log.error("refused to execute shell command '#{j['s']}' for #{@user} (#{peer_ip}:#{peer_port})")
211
- send_data({:sc => -1})
212
- send_last_prompt
213
- else
214
- @log.warn("executing shell command '#{j['s']}' for #{@user} (#{peer_ip}:#{peer_port})")
215
- @shell_cmd = EM.popen3(j['s'], ShellCmd, self)
216
- end
264
+ def receive_shell_cmd(cmd)
265
+ return if require_auth
266
+ unless @allow_shell_cmds
267
+ puts "\033[1mshell commands are not allowed by this server\033[0m"
268
+ @log.error("refused to execute shell command '#{cmd}' for #{@user} (#{peer_ip}:#{peer_port})")
269
+ send_shell_result(-1)
270
+ send_last_prompt
271
+ else
272
+ @log.warn("executing shell command '#{cmd}' for #{@user} (#{peer_ip}:#{peer_port})")
273
+ @shell_cmd = EM.popen3(cmd, ShellCmd, self)
274
+ end
275
+ end
217
276
 
218
- elsif j['sd'] # shell data
219
- @shell_cmd.send_data(j['sd'])
277
+ def receive_shell_data(d)
278
+ return if require_auth
279
+ @shell_cmd.send_data(d)
280
+ end
220
281
 
221
- elsif j['ssc'] # shell ctrl-c
222
- @shell_cmd.close_connection
282
+ def receive_shell_sig(type)
283
+ return if require_auth
284
+ type == :term && @shell_cmd.close_connection
285
+ end
223
286
 
224
- else
225
- warn "received unexpected data: #{j.inspect}"
226
- end # j['d']
227
- end # receive_json(j)
287
+ def receive_unknown(j)
288
+ return if require_auth
289
+ warn "received unexpected data: #{j.inspect}"
290
+ send_error("received unexpected data: #{j.inspect}")
291
+ send_last_prompt
292
+ end
228
293
 
294
+ def require_auth
295
+ return false if !@auth_required
296
+ send_auth(false)
297
+ true
298
+ end
229
299
 
230
300
  def authenticated!
231
301
  while (aa = @after_auth.shift)
232
- send_data(aa)
302
+ aa.call
233
303
  end
234
304
  end
235
305
 
@@ -246,19 +316,24 @@ module PryRemoteEm
246
316
  end
247
317
 
248
318
  def send_last_prompt
249
- @auth_required ? @after_auth.push({:p => @last_prompt}) : send_data({:p => @last_prompt})
319
+ @auth_required ? (after_auth { send_prompt(@last_prompt) }) : send_prompt(@last_prompt)
320
+ end
321
+
322
+ def after_auth(&blk)
323
+ # TODO perhaps replace with #auth_ok
324
+ @after_auth.push(blk)
250
325
  end
251
326
 
252
327
  # Sends a chat message to the client.
253
328
  def send_message(msg, from = nil)
254
329
  msg = "#{msg} (@#{from})" unless from.nil?
255
- @auth_required ? @after_auth.push({:m => msg}) : send_data({:m => msg})
330
+ @auth_required ? (after_auth {send_msg(msg)}) : send_msg(msg)
256
331
  end
257
332
  #
258
333
  # Sends a chat message to the client.
259
334
  def send_bmessage(msg, from = nil)
260
335
  msg = "#{msg} (@#{from})" unless from.nil?
261
- @auth_required ? @after_auth.push({:mb => msg}) : send_data({:mb => msg})
336
+ @auth_required ? (after_auth {send_msg_bcast(msg)}) : send_msg_bcast(msg)
262
337
  end
263
338
 
264
339
  # Callbacks for events on the server
@@ -299,19 +374,22 @@ module PryRemoteEm
299
374
  end
300
375
  end # auth_fail(*args, &blk)
301
376
 
377
+ def send_error(msg)
378
+ puts "\033[31m#{msg}\033[0m"
379
+ end
302
380
 
303
381
  # Methods that make Server compatible with Pry
304
382
 
305
383
  def readline(prompt)
306
384
  @last_prompt = prompt
307
- @auth_required ? @after_auth.push({:p => prompt}) : send_data({:p => prompt})
385
+ @auth_required ? (after_auth { send_prompt(prompt) }) : send_prompt(prompt)
308
386
  return @lines.shift unless @lines.empty?
309
387
  @waiting = Fiber.current
310
388
  return Fiber.yield
311
389
  end
312
390
 
313
391
  def print(val)
314
- @auth_required ? @after_auth.push({:d => val}) : send_data({:d => val})
392
+ @auth_required ? (after_auth { send_raw(val) }) : send_raw(val)
315
393
  end
316
394
  alias :write :print
317
395