class Syndi::IRC::Server

A class which maintains a connection to an IRC server and provides a highly usable interface for the IRC server.

@api IRC @since 4.0.0 @author noxgirl

@!attribute [r] socket

@return [TCPSocket] The TCP socket being used for the connection.

@!attribute [r] in

@return [Integer] The number of bytes received from the socket.

@!attribute [r] out

@return [Integer] The number of bytes sent to the socket.

@!attribute [r] type

@return [Symbol] +:irc+

@!attribute [r] supp

@return [Syndi::IRC::State::Support] The IRCd capabilities.

@!attribute name

@return [String] The name of the server as specified by configuration.

@!attribute address

@return [String] The address used to connect to the server.

@!attribute port

@return [Integer] The port used to connect to the server

@!attribute nick

@return [String] The nickname of the bot on the server.

@!attribute user

@return [String] The username of the bot on the server.

@!attribute real

@return [String] The real name or GECOS of the bot on the server.

@!attribute password

@return [String] If needed, the password used to connect to the server
@return [nil] If not needed.

@!attribute bind

@return [String] If desired, the address to which to bind for this socket
@return [nil] If not desired.
@note This appears to be unused at the moment.

@!attribute ssl

@return [true, false] If SSL should [not] be used for the connection.

@!attribute sasl_id

@return [String] If SASL is desired, the username with which to authenticate.
@return [nil] If not used.
@note This is seemingly deprecated?

@!attribute connected

@return [true, false] Whether or not we are connected to the server.

@!attribute mask

@return [String] The bot's own hostname or mask on the IRC server.

@!attribute recvq

 @return [Array<String>] The socket's receive queue, which is comprised of an array
   of strings which are pending processing.

@!attribute prefixes
 @return [Hash{String => String}] The IRC server's supported prefixes, with the key being
   the channel mode which represents the prefix, and the value being the prefix.

@!attribute channel_modes

@return [Hash{Symbol => Array<String>}] The IRC server's supported channel modes, divided as thus:

  - +:list+   = A list of modes which add/remove a nickname or mask from a channel list, such as ops and bans.
  - +:always+ = A llst of modes which change a channel setting, and always have a parameter.
  - +:set+    = A list of modes which change a channel setting, and which have a parameter only when set.
  - +:never+ = A list of modes which change a channel setting, and which never have a parameter.

@!attribute max_modes

@return [Integer] The maximum number of mode changes which may be specified in a /MODE query.

@!attribute await_self_who

@return [true, false] Whether or not we are awaiting for a response to a /WHO on ourselves.

@!attribute channels

@return [Hash{String => IRC::Object::Channel}] A list of channels in which we reside,
  with each key being the channel's name in all-lowercase, and the respective values
  being of {IRC::Object::Channel IRC::Object::Channel}.

@!attribute users

@return [Hash{String => IRC::Object::User}] A list of users who are known to us,
  with each key being the user's nickname in all-lowercase, and the respective values
  being of {IRC::Object::User IRC::Object::User}.

Attributes

address[RW]
bind[RW]
chans[RW]
connected[RW]
in[R]
name[RW]
nick[RW]
out[R]
password[RW]
port[RW]
real[RW]
socket[R]
ssl[RW]
supp[R]
type[R]
user[RW]
users[RW]

Public Class Methods

new(name) { |self| ... } click to toggle source

Produce a new instance of {Syndi::IRC::Server}.

@param [String] name The name of the server to which we should connect.

@yieldparam [Syndi::IRC::Server] c This instance, intended for configuration of the

attributes.

Configuration attributes are address, port, nick, user, real, password, bind, and ssl.

@example

irc = Syndi::IRC::Server.new('Freenode') do |c|
  c.address = 'irc.freenode.net'
  c.port    = 7000
  c.nick    = 'cowmoon'
  c.user    = 'foo1'
  c.real    = "The night is lovely."
  c.bind    = 'localhost'
  c.ssl     = true
end
# File lib/syndi/irc/server.rb, line 141
def initialize(name)

  # Prepare attributes.
  @name     = name
  @address  = nil
  @port     = nil
  @nick     = nil
  @user     = nil
  @real     = nil
  @password = nil
  @bind     = nil
  @ssl      = false

  # Yield for configuration.
  yield(self) if block_given? or raise ArgumentError, "Server #{name} unable to initialize because it was not configured."

  # Additional instance attributes.
  @in         = 0
  @out        = 0
  @socket     = nil
  @connected  = false
  @type       = :irc

  # Pull in commands.
  extend   Syndi::IRC::Std::Commands
  # State managers.
  @supp  = Syndi::IRC::State::Support.new
  @chans = nil
  @users = nil

  # Our receive queue remainder.
  @recv_rem = nil

  # Mutual exclusion for thread safety.
  @lock = Mutex.new

end

Public Instance Methods

connect() click to toggle source

Establish (or attempt to) a connection with the server.

# File lib/syndi/irc/server.rb, line 180
def connect

  # Check for missing attributes.
  begin
    attribute_check
  rescue => e
    $m.error("Cannot connect to server #@name: #{e}", false, e.backtrace)
  end

  $m.info("Connecting to #@name @ #@address:#@port...")

  # Create a new socket.
  begin
    socket = TCPSocket.new(@address, @port, @bind)
  rescue => e
    $m.error("Failed to connect to server #@name: #{e}", false, e.backtrace)
    raise
  end

  # Wrap it in SSL if told to.
  if ssl
    begin
      socket = OpenSSL::SSL::SSLSocket.new(socket)
      socket.connect
    rescue => e
      $m.error("Failed to connect to server #@name: #{e}", false, e.backtrace)
      raise
    end
  end

  @socket = socket

  # Register.
  emit :irc, :preconnect, self
  pass @password if @password
  snd 'CAP LS'
  self.nickname = @nick
  user @user, Socket.gethostname, @address, @real

end
inspect() click to toggle source
# File lib/syndi/irc/server.rb, line 270
def inspect; "#<Syndi::IRC::Server: name='#@name'>"; end
recv() click to toggle source

Receive data from the socket, and push it into the recvQ.

# File lib/syndi/irc/server.rb, line 231
def recv

  # Thread safety.
  @lock.synchronize do
  
    if @socket.nil? or @socket.eof?
      return
    end

    # Read the data.
    data = @socket.sysread(1024)
    # Increase in.
    @in += data.length

    # Split the data.
    recv = []
    until data !~ /\r\n/
      line, data = data.split(/(?<=\r\n)/, 2)
      recv.push line.chomp "\r\n"
    end

    # Check if there's a remainder in the recvQ.
    if @recv_rem != ''
      recv[0] = "#@recv_rem#{recv[0]}"
      @recv_rem = ''
    end
    @recv_rem = data if data != ''

    # Lastly, sent the data out
    recv.each do |dline|
      $m.foreground("{irc-recv} #@name >> #{dline}")
      emit :irc, :receive, self, dline # send it out to :receive
    end
  
  end

end
s()
Alias for: to_s
snd(data) click to toggle source

Send data to the socket.

@param [String] data The string of data, which should not exceed 512 in length.

# File lib/syndi/irc/server.rb, line 224
def snd data
  $m.foreground("{irc-send} #@name << #{data}")
  @socket.write("#{data}\r\n")
  @out += "#{data}\r\n".length
end
to_s() click to toggle source
# File lib/syndi/irc/server.rb, line 269
def to_s;    @name; end
Also aliased as: s

Private Instance Methods

attribute_check() click to toggle source

Check the presence of all attributes.

# File lib/syndi/irc/server.rb, line 278
def attribute_check
  raise(ConfigError, "Missing server address")  unless @address
  raise(ConfigError, "Missing server port")     unless @port
  raise(ConfigError, "Missing nickname to use") unless @nick
  raise(ConfigError, "Missing username to use") unless @user
  raise(ConfigError, "Missing realname to use") unless @real
end
connected?() click to toggle source

Check if we are connected.

@return [true, false]

# File lib/syndi/irc/server.rb, line 289
def connected?
  return false unless @socket
  return false unless @connected
  true
end