Included Modules

PryRemoteEm::Server

Public Class Methods

new(obj, opts = {:tls => false}) click to toggle source
# File lib/pry-remote-em/server.rb, line 135
def initialize(obj, opts = {:tls => false})
  @obj              = obj
  @opts             = opts
  @allow_shell_cmds = opts[:allow_shell_cmds]
  @log              = opts[:logger] || ::Logger.new(STDERR)
  # Blocks that will be called on each authentication attempt, prior checking the credentials
  @auth_attempt_cbs = []
  # All authentication attempts that occured before an auth callback was registered
  @auth_attempts    = []
  # Blocks that will be called on each failed authentication attempt
  @auth_fail_cbs    = []
  # All failed authentication attempts that occured before an auth callback was reigstered
  @auth_fails       = []
  # Blocks that will be called on successful authentication attempt
  @auth_ok_cbs      = []
  # All successful authentication attemps that occured before the auth ok callbacks were registered
  @auth_oks         = []

  # The number maximum number of authentication attempts that are permitted
  @auth_tries       = 5
  # Data to be sent after the user successfully authenticates if authentication is required
  @after_auth       = []
  return unless (a = opts[:auth])
  if a.is_a?(Proc)
    return fail("auth handler Procs must take two arguments not (#{a.arity})") unless a.arity == 2
    @auth = a
  elsif a.respond_to?(:call)
    return fail("auth handler must take two arguments not (#{a.method(:call).arity})") unless a.method(:call).arity == 2
    @auth = a
  else
    return error("auth handler objects must respond to :call, or :[]") unless a.respond_to?(:[])
    @auth = lambda {|u,p| a[u] && a[u] == p }
  end
end
peers(obj = nil) click to toggle source

The list of pry-remote-em connections for a given object, or the list of all pry-remote-em connections for this process. The peer list is used when broadcasting messages between connections.

# File lib/pry-remote-em/server.rb, line 119
def peers(obj = nil)
  @peers ||= {}
  obj.nil? ? @peers.values.flatten : (@peers[obj] ||= [])
end
register(obj, peer) click to toggle source

Record the association between a given object and a given pry-remote-em connection.

# File lib/pry-remote-em/server.rb, line 125
def register(obj, peer)
  peers(obj).tap { |plist| plist.include?(peer) || plist.push(peer) }
end
run(obj, host = DEFHOST, port = DEFPORT, opts = {:tls => false}) click to toggle source

Start a pry-remote-em server @param [Object] obj the object to bind pry to @param [String] ip the ip address to listen on @param [Fixnum, Symbol] port the port to listen on - if :auto the next available port will be taken @param [Hash] opts @option opts [Boolean] :tls require SSL encryption @option opts [Logger] :logger @option opts [Proc, Object] :auth require user authentication - see README @option opts [Boolean] :allow_shell_cmds

# File lib/pry-remote-em/server.rb, line 77
def run(obj, host = DEFHOST, port = DEFPORT, opts = {:tls => false})
  tries = [port, opts[:port_fail]].include?(:auto) ? 100 : 1
  port  = DEFPORT if :auto == port
  # TODO raise a useful exception not RuntimeError
  raise "root permission required for port below 1024 (#{port})" if port < 1024 && Process.euid != 0
  begin
    server = EM.start_server(host, port, PryRemoteEm::Server, obj, opts) do |pre|
      Fiber.new {
        begin
          yield pre if block_given?
          Pry.start(obj, :input => pre, :output => pre)
        ensure
          pre.close_connection
        end
      }.resume
    end
  rescue => e
    # EM 1.0.0.beta4's message tells us the port is in use; 0.12.10 just says, 'no acceptor'
    if (e.message.include?('port is in use') || e.message.include?('no acceptor')) && tries > 1
      tries -= 1
      port += 1
      retry
    end
    raise "can't bind to #{host}:#{port} - #{e}"
  end
  url    = "#{opts[:tls] ? 'pryems' : 'pryem'}://#{host}:#{port}/"
  name   = obj.send(:eval, 'self') rescue "#{obj}"
  name   = Pry.view_clip(name)
  PryRemoteEm.servers[url] = [server, name]
  (opts[:logger] || ::Logger.new(STDERR)).info("[pry-remote-em] listening for connections on #{url}")
  Broker.run(opts[:broker_host] || ENV['PRYEMBROKER'] || DEF_BROKERHOST, opts[:broker_port] || ENV['PRYEMBROKERPORT'] || DEF_BROKERPORT, opts) do |broker|
    broker.register(url, name)
    rereg = EM::PeriodicTimer.new(15) do
      EM.get_sockname(server) ? broker.register(url, name) : nil #rereg.cancel
    end
  end # broker
  url
end
unregister(obj, peer) click to toggle source

Remove the association between a given object and a given pry-remote-em connection.

# File lib/pry-remote-em/server.rb, line 130
def unregister(obj, peer)
  peers(obj).tap {|plist| true while plist.delete(peer) }
end

Public Instance Methods

after_auth(&blk) click to toggle source
# File lib/pry-remote-em/server.rb, line 319
def after_auth(&blk)
  # TODO perhaps replace with #auth_ok
  @after_auth.push(blk)
end
auth_attempt(*args, &blk) click to toggle source

Registers a block to call when authentication is attempted. @overload auth_attempt(&blk)

@yield [user, ip] a block to call on each authentication attempt
@yieldparam [String] user
@yieldparam [String] ip
# File lib/pry-remote-em/server.rb, line 343
def auth_attempt(*args, &blk)
  block_given? ? @auth_attempt_cbs << blk : @auth_attempts.push(args)
  while (auth_data = @auth_attempts.shift)
    @auth_attempt_cbs.each { |cb| cb.call(*auth_data) }
  end
end
auth_fail(*args, &blk) click to toggle source

Registers a block to call when authentication fails. @overload auth_fail(&blk)

@yield [user, ip] a block to call after each failed authentication attempt
@yieldparam [String] user
@yieldparam [String] ip
# File lib/pry-remote-em/server.rb, line 355
def auth_fail(*args, &blk)
  block_given? ? @auth_fail_cbs << blk : @auth_fails.push(args)
  while (fail_data = @auth_fails.shift)
    @auth_fail_cbs.each { |cb| cb.call(*fail_data) }
  end
end
auth_ok(*args, &blk) click to toggle source

Registers a block to call when authentication succeeds. @overload auth_ok(&blk)

@yield [user, ip] a block to call after each successful authentication attempt
@yieldparam [String] user
@yieldparam [String] ip
# File lib/pry-remote-em/server.rb, line 367
def auth_ok(*args, &blk)
  block_given? ? @auth_ok_cbs << blk : @auth_oks.push(args)
  while (ok_data = @auth_oks.shift)
    @auth_ok_cbs.each { |cb| cb.call(*ok_data) }
  end
end
authenticated!() click to toggle source
# File lib/pry-remote-em/server.rb, line 297
def authenticated!
  while (aa = @after_auth.shift)
    aa.call
  end
end
completion_proc=(compl) click to toggle source
# File lib/pry-remote-em/server.rb, line 398
def completion_proc=(compl)
  @compl_proc = compl
end
flush() click to toggle source
# File lib/pry-remote-em/server.rb, line 406
def flush
  true
end
peer_ip() click to toggle source
# File lib/pry-remote-em/server.rb, line 198
def peer_ip
  return @peer_ip if @peer_ip
  return "" if get_peername.nil?
  @peer_port, @peer_ip = Socket.unpack_sockaddr_in(get_peername)
  @peer_ip
end
peer_port() click to toggle source
# File lib/pry-remote-em/server.rb, line 205
def peer_port
  return @peer_port if @peer_port
  return "" if get_peername.nil?
  @peer_port, @peer_ip = Socket.unpack_sockaddr_in(get_peername)
  @peer_port
end
peers(all = false) click to toggle source
# File lib/pry-remote-em/server.rb, line 309
def peers(all = false)
  plist = (all ? PryRemoteEm::Server.peers : PryRemoteEm::Server.peers(@obj)).clone
  plist.delete(self)
  plist
end
post_init() click to toggle source
# File lib/pry-remote-em/server.rb, line 175
def post_init
  @lines = []
  Pry.config.pager, @old_pager = false, Pry.config.pager
  @auth_required  = @auth
  port, ip        = Socket.unpack_sockaddr_in(get_peername)
  @log.info("[pry-remote-em] received client connection from #{ip}:#{port}")
  # TODO include first level prompt in banner
  send_banner("PryRemoteEm #{VERSION} #{@opts[:tls] ? 'pryems' : 'pryem'}")
  @log.info("#{url} PryRemoteEm #{VERSION} #{@opts[:tls] ? 'pryems' : 'pryem'}")
  @opts[:tls] ? start_tls : (@auth_required && send_auth(false))
  PryRemoteEm::Server.register(@obj, self)
end
puts(data = "") click to toggle source
# File lib/pry-remote-em/server.rb, line 393
def puts(data = "")
  s = data.to_s
  print(s[0] == "\n" ? s : s + "\n")
end
readline(prompt) click to toggle source

Methods that make Server compatible with Pry

# File lib/pry-remote-em/server.rb, line 380
def readline(prompt)
  @last_prompt = prompt
  @auth_required ? (after_auth { send_prompt(prompt) }) : send_prompt(prompt)
  return @lines.shift unless @lines.empty?
  @waiting = Fiber.current
  return Fiber.yield
end
receive_auth(user, pass) click to toggle source
# File lib/pry-remote-em/server.rb, line 228
def receive_auth(user, pass)
  return send_auth(true) if !@auth || !@auth_required
  return send_auth('auth data must include a user and pass') if user.nil? || pass.nil?
  auth_attempt(user, peer_ip)
  unless (@auth_required = !@auth.call(user, pass))
    @user = user
    auth_ok(user, peer_ip)
    authenticated!
  else
   auth_fail(user, peer_ip)
    if @auth_tries <= 0
      msg = "max authentication attempts reached"
      send_auth(msg)
      @log.debug("[pry-remote-em] #{msg} (#{peer_ip}:#{peer_port})")
      return close_connection_after_writing
    end
    @auth_tries -= 1
  end
  return send_auth(!@auth_required)
end
receive_completion(c) click to toggle source

tab completion request

# File lib/pry-remote-em/server.rb, line 223
def receive_completion(c)
  return if require_auth
  send_completion(@compl_proc.call(c))
end
receive_msg(m) click to toggle source
# File lib/pry-remote-em/server.rb, line 249
def receive_msg(m)
  return if require_auth
  peers.each { |peer| peer.send_message(m, @user) }
  send_last_prompt
end
receive_msg_bcast(mb) click to toggle source
# File lib/pry-remote-em/server.rb, line 255
def receive_msg_bcast(mb)
  return if require_auth
  peers(:all).each { |peer| peer.send_bmessage(mb, @user) }
  send_last_prompt
end
receive_raw(d) click to toggle source
# File lib/pry-remote-em/server.rb, line 212
def receive_raw(d)
  return if require_auth
  return send_last_prompt if d.nil? || d.empty?
  @lines.push(*d.split("\n"))
  if @waiting
    f, @waiting = @waiting, nil
    f.resume(@lines.shift)
  end
end
receive_shell_cmd(cmd) click to toggle source
# File lib/pry-remote-em/server.rb, line 261
def receive_shell_cmd(cmd)
  return if require_auth
  unless @allow_shell_cmds
    puts "\0033[1mshell commands are not allowed by this server\0033[0m"
    @log.error("refused to execute shell command '#{cmd}' for #{@user} (#{peer_ip}:#{peer_port})")
    send_shell_result(-1)
    send_last_prompt
  else
    @log.warn("executing shell command '#{cmd}' for #{@user} (#{peer_ip}:#{peer_port})")
    @shell_cmd = EM.popen3(cmd, ShellCmd, self)
  end
end
receive_shell_data(d) click to toggle source
# File lib/pry-remote-em/server.rb, line 274
def receive_shell_data(d)
  return if require_auth
  @shell_cmd.send_data(d)
end
receive_shell_sig(type) click to toggle source
# File lib/pry-remote-em/server.rb, line 279
def receive_shell_sig(type)
  return if require_auth
  type == :term && @shell_cmd.close_connection
end
receive_unknown(j) click to toggle source
# File lib/pry-remote-em/server.rb, line 284
def receive_unknown(j)
  return if require_auth
  warn "received unexpected data: #{j.inspect}"
  send_error("received unexpected data: #{j.inspect}")
  send_last_prompt
end
require_auth() click to toggle source
# File lib/pry-remote-em/server.rb, line 291
def require_auth
  return false if !@auth_required
  send_auth(false)
  true
end
send_bmessage(msg, from = nil) click to toggle source

Sends a chat message to the client.

# File lib/pry-remote-em/server.rb, line 331
def send_bmessage(msg, from = nil)
  msg = "#{msg} (@#{from})" unless from.nil?
  @auth_required ?  (after_auth {send_msg_bcast(msg)}) : send_msg_bcast(msg)
end
send_error(msg) click to toggle source
# File lib/pry-remote-em/server.rb, line 374
def send_error(msg)
  puts "\0033[31m#{msg}\0033[0m"
end
send_last_prompt() click to toggle source
# File lib/pry-remote-em/server.rb, line 315
def send_last_prompt
  @auth_required ? (after_auth { send_prompt(@last_prompt) }) :  send_prompt(@last_prompt)
end
send_message(msg, from = nil) click to toggle source

Sends a chat message to the client.

# File lib/pry-remote-em/server.rb, line 325
def send_message(msg, from = nil)
  msg = "#{msg} (@#{from})" unless from.nil?
  @auth_required ?  (after_auth {send_msg(msg)}) : send_msg(msg)
end
ssl_handshake_completed() click to toggle source
# File lib/pry-remote-em/server.rb, line 193
def ssl_handshake_completed
  @log.info("[pry-remote-em] TLS connection established (#{peer_ip}:#{peer_port})")
  send_auth(false) if @auth_required
end
start_tls() click to toggle source
# File lib/pry-remote-em/server.rb, line 188
def start_tls
  @log.debug("[pry-remote-em] starting TLS (#{peer_ip}:#{peer_port})")
  super(@opts[:tls].is_a?(Hash) ? @opts[:tls] : {})
end
tty?() click to toggle source
# File lib/pry-remote-em/server.rb, line 402
def tty?
  true # might be a very bad idea ....
end
unbind() click to toggle source
# File lib/pry-remote-em/server.rb, line 303
def unbind
  Pry.config.pager  = @old_pager
  PryRemoteEm::Server.unregister(@obj, self)
  @log.debug("[pry-remote-em] remote session terminated (#{peer_ip}:#{peer_port})")
end
url() click to toggle source
# File lib/pry-remote-em/server.rb, line 170
def url
  port, host = Socket.unpack_sockaddr_in(get_sockname)
  "#{@opts[:tls] ? 'pryems' : 'pryem'}://#{host}:#{port}/"
end
write(val) click to toggle source
Alias for: print

[Validate]

Generated with the Darkfish Rdoc Generator 2.