Parent

Namespace

Class/Module Index [+]

Quicksearch

Irc::Socket

wrapped TCPSocket for communication with the server. emulates a subset of TCPSocket functionality

Attributes

bytes_received[R]

total number of bytes received from the irc server

bytes_sent[R]

total number of bytes sent to the irc server

filter[R]

an optional filter object. we call @filter.in(data) for all incoming data and @filter.out(data) for all outgoing data

lines_received[R]

total number of lines received from the irc server

lines_sent[R]

total number of lines sent to the irc server

penalty_pct[RW]

penalty multiplier (percent)

server_uri[R]

normalized uri of the current server

throttle_bytes[R]

accumulator for the throttle

Public Class Methods

new(server_list, host, opts={}) click to toggle source

server_list

list of servers to connect to

host

optional local host to bind to (ruby 1.7+ required)

create a new Irc::Socket

# File lib/rbot/ircsocket.rb, line 277
def initialize(server_list, host, opts={})
  @server_list = server_list.dup
  @server_uri = nil
  @conn_count = 0
  @host = host
  @sock = nil
  @filter = IdentityFilter.new
  @spooler = false
  @lines_sent = 0
  @lines_received = 0
  @ssl = opts[:ssl]
  @penalty_pct = opts[:penalty_pct] || 100
end

Public Instance Methods

clearq() click to toggle source
# File lib/rbot/ircsocket.rb, line 379
def clearq
  @sendq.clear
end
connect() click to toggle source

open a TCP connection to the server

# File lib/rbot/ircsocket.rb, line 296
def connect
  if connected?
    warning "reconnecting while connected"
    return
  end
  srv_uri = @server_list[@conn_count % @server_list.size].dup
  srv_uri = 'irc://' + srv_uri if !(srv_uri =~ /:\/\//)
  @conn_count += 1
  @server_uri = URI.parse(srv_uri)
  @server_uri.port = 6667 if !@server_uri.port
  debug "connection attempt \##{@conn_count} (#{@server_uri.host}:#{@server_uri.port})"

  if(@host)
    begin
      sock=TCPSocket.new(@server_uri.host, @server_uri.port, @host)
    rescue ArgumentError => e
      error "Your version of ruby does not support binding to a "
      error "specific local address, please upgrade if you wish "
      error "to use HOST = foo"
      error "(this option has been disabled in order to continue)"
      sock=TCPSocket.new(@server_uri.host, @server_uri.port)
    end
  else
    sock=TCPSocket.new(@server_uri.host, @server_uri.port)
  end
  if(@ssl)
    require 'openssl'
    ssl_context = OpenSSL::SSL::SSLContext.new()
    ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE
    sock = OpenSSL::SSL::SSLSocket.new(sock, ssl_context)
    sock.sync_close = true
    sock.connect
  end
  @sock = sock
  @last_send = Time.new
  @flood_send = Time.new
  @burst = 0
  @sock.extend(MonitorMixin)
  @sendq = MessageQueue.new
  @qthread = Thread.new { writer_loop }
end
connected?() click to toggle source
# File lib/rbot/ircsocket.rb, line 291
def connected?
  !@sock.nil?
end
emergency_puts(message, penalty = false) click to toggle source

used to send lines to the remote IRCd by skipping the queue message: IRC message to send it should only be used for stuff that *must not* be queued, i.e. the initial PASS, NICK and USER command or the final QUIT message

# File lib/rbot/ircsocket.rb, line 343
def emergency_puts(message, penalty = false)
  @sock.synchronize do
    # debug "In puts - got @sock"
    puts_critical(message, penalty)
  end
end
filter=(f) click to toggle source

set filter to identity, not to nil

# File lib/rbot/ircsocket.rb, line 270
def filter=(f)
    @filter = f || IdentityFilter.new
end
flush() click to toggle source

flush the TCPSocket

# File lib/rbot/ircsocket.rb, line 384
def flush
  @sock.flush
end
gets() click to toggle source

get the next line from the server (blocks)

# File lib/rbot/ircsocket.rb, line 359
def gets
  if @sock.nil?
    warning "socket get attempted while closed"
    return nil
  end
  begin
    reply = @filter.in(@sock.gets)
    @lines_received += 1
    reply.strip! if reply
    debug "RECV: #{reply.inspect}"
    return reply
  rescue Exception => e
    handle_socket_error(:RECV, e)
  end
end
handle_socket_error(string, e) click to toggle source
# File lib/rbot/ircsocket.rb, line 350
def handle_socket_error(string, e)
  error "#{string} failed: #{e.pretty_inspect}"
  # We assume that an error means that there are connection
  # problems and that we should reconnect, so we
  shutdown
  raise SocketError.new(e.inspect)
end
queue(msg, chan=nil, ring=0) click to toggle source
# File lib/rbot/ircsocket.rb, line 375
def queue(msg, chan=nil, ring=0)
  @sendq.push msg, chan, ring
end
select(timeout=nil) click to toggle source

Wraps Kernel.select on the socket

# File lib/rbot/ircsocket.rb, line 389
def select(timeout=nil)
  Kernel.select([@sock], nil, nil, timeout)
end
shutdown(how=2) click to toggle source

shutdown the connection to the server

# File lib/rbot/ircsocket.rb, line 394
def shutdown(how=2)
  return unless connected?
  @qthread.kill
  @qthread = nil
  begin
    @sock.close
  rescue Exception => e
    error "error while shutting down: #{e.pretty_inspect}"
  end
  @sock = nil
  @sendq.clear
end

Private Instance Methods

puts_critical(message, penalty=false) click to toggle source

same as puts, but expects to be called with a lock held on @sock

# File lib/rbot/ircsocket.rb, line 431
def puts_critical(message, penalty=false)
  # debug "in puts_critical"
  begin
    debug "SEND: #{message.inspect}"
    if @sock.nil?
      error "SEND attempted on closed socket"
    else
      # we use Socket#syswrite() instead of Socket#puts() because
      # the latter is racy and can cause double message output in
      # some circumstances
      actual = @filter.out(message) + "\n"
      now = Time.new
      @sock.syswrite actual
      @last_send = now
      @flood_send = now if @flood_send < now
      @flood_send += message.irc_send_penalty*@penalty_pct/100.0 if penalty
      @lines_sent += 1
    end
  rescue Exception => e
    handle_socket_error(:SEND, e)
  end
end
writer_loop() click to toggle source
# File lib/rbot/ircsocket.rb, line 409
def writer_loop
  loop do
    begin
      now = Time.now
      flood_delay = @flood_send - MAX_IRC_SEND_PENALTY - now
      delay = [flood_delay, 0].max
      if delay > 0
        debug "sleep(#{delay}) # (f: #{flood_delay})"
        sleep(delay)
      end
      msg = @sendq.shift
      debug "got #{msg.inspect} from queue, sending"
      emergency_puts(msg, true)
    rescue Exception => e
      error "Spooling failed: #{e.pretty_inspect}"
      debug e.backtrace.join("\n")
      raise e
    end
  end
end

[Validate]

Generated with the Darkfish Rdoc Generator 2.