class Fantasy::IRC

Attributes

connected[R]
events[R]
loggedin[R]
plugins[R]
rooms[R]
session[R]
started[R]
users[R]

Public Class Methods

new(options={}) click to toggle source
# File lib/fantasy-irc/irc.rb, line 10
def initialize options={}
    $bot = self
    @data = Hash.new
    @started = Time.now.to_i
    @running = 0
    @loggedin = 0
    @connected = 0
    @prefix = options[:prefix] || '!'

    @events = Event::Factory.new
    @rooms = Room::Factory.new self
    @users = User::Factory.new self
    @plugins = Plugins.new

    %w{tick loggedin connected user_joined user_parted user_quit channel_message}.each do |e|
        @events.create(e)
    end
end

Public Instance Methods

cleanup() click to toggle source
# File lib/fantasy-irc/irc.rb, line 89
def cleanup
    puts "[!][Cleanup] Closing socket."
    @data[:socket].close()
end
connect(data) click to toggle source
# File lib/fantasy-irc/irc.rb, line 64
def connect data
    if not data[:server] then
        raise "you need to specify :server on connect"
    end
    if not data[:ssl] then
        data[:ssl] = false
    end
    if not data[:port] then
        data[:port] = data[:ssl] ? 6697 : 6667
    end

    # Connect to the chat server
    @data[:socket] = @data[:realsocket] = TCPSocket.open(data[:server], data[:port])

    if !!data[:ssl] then
        @data[:socket] = OpenSSL::SSL::SSLSocket.new(@data[:realsocket])
        @data[:socket].connect
    end

    @connected = Time.now.to_i
    self.events.by_name('connected').call

    return @data[:socket]
end
login(data) click to toggle source
# File lib/fantasy-irc/irc.rb, line 29
def login data
    if not data[:nickname] and data[:username] then
        data[:nickname] = data[:username]
    end
    if not data[:username] and data[:nickname] then
        data[:username] = data[:nickname]
    end
    if not data[:realname] then
        data[:realname] = "https://rubygems.org/gems/fantasy-irc"
    end

    if not data[:nickname] then
        raise "you need to specify :nickname and/or :username on login"
    end

    if data[:password] then
        self.send("PASS #{data[:password]}")
    end

    self.send("USER #{data[:username]} fantasy fantasy :#{data[:realname]}")
    self.send("NICK #{data[:nickname]}")
end
parse(s) click to toggle source
# File lib/fantasy-irc/irc.rb, line 94
def parse(s)
    s.chomp!

    if (s[0,4] == "PING") then
        tok = s.split(' ', 2)
        self.send "PONG #{tok[1]}"

    elsif (s[0,1] == ":") then
        # Server stuff
        tok = s.split(' ', 4)

        if (tok[1] == "001") then
            # loggedin
            @loggedin = Time.now.to_i
            # ignore ourself
            self.users.create(tok[2]).ignore!
            self.events.by_name('loggedin').call

        elsif (tok[1] == "JOIN") then
            # user joined
            room_name = tok[2].gsub(/^:/, '') # remove leadig : (on some networks, but not all!)
            room = self.rooms.by_name(room_name)
            user = self.users.create(tok[0][1,tok[0].length])

            # add user to room and room to user
            room.users << user
            user.rooms << room

            return if user.ignored?

            self.events.by_name('user_joined').call([room, user])

        elsif (tok[1] == "PRIVMSG") then
            # channel or private message
            if (tok[2][0,1] == "#") then
                # channel message
                room = self.rooms.by_name(tok[2])
                user = self.users.create(tok[0][1,tok[0].length])

                # add user to room and room to user
                room.users << user
                user.rooms << room

                return if user.ignored?

                text = tok[3][1,tok[3].length]
                self.events.by_name('channel_message').call([room, user, text])

                if text[0] == @prefix then
                    command, args = text.split(' ', 2)
                    self.plugins.command(command[1,command.length], {:room => room, :user => user}, args)
                end
            end

        elsif (tok[1] == "PART") then
            # user parted
            room = self.rooms.by_name(tok[2])
            user = self.users.create(tok[0][1,tok[0].length])

            # remove user from room and room from user
            room.users.delete user
            user.rooms.delete room

            return if user.ignored?

            # TODO part text?
            self.events.by_name('user_parted').call([room, user])

        elsif (tok[1] == "QUIT") then
            # user quit
            user = self.users.create(tok[0][1,tok[0].length])

            puts "!!! user #{user} quit."
            # remove user from all rooms
            self.rooms.all.values.each do |r|
                r.users.delete user
            end
            user.reset

            self.events.by_name('user_quit').call([user])

        else

            # puts "[!] UNKNOWN PROTOCOL PART: #{s}"
        end
    else

        puts "[!] UNKNOWN PROTOCOL PART: #{s}"
    end
end
run() click to toggle source
# File lib/fantasy-irc/irc.rb, line 185
def run
    if @running.nonzero? then
        return false
    end

    @running = Time.now.to_i
    last_tick = @running
    last_ping = @running

    loop do
        time_now = Time.now

        # tick every second
        if time_now.to_i > last_tick then
            self.events.by_name('tick').call(time_now)
            last_tick = time_now.to_i
        end

        # chatserver ping, every 5 minutes
        if @connected.nonzero? and time_now.to_i-300 >= last_ping then
            self.send("PING :"+time_now.to_f.to_s)
            last_ping = time_now.to_i
        end

        # connection
        if @connected.nonzero? then
            ready = select([@data[:socket]], nil, nil, 0.1)
            next if !ready
            for s in ready[0]
                if s == @data[:socket] then
                    return if @data[:socket].eof # XXX?
                    s = @data[:socket].gets
                    puts "--> #{s}"
                    self.parse(s)
                end
            end
        else # no connection, less cpu usage
            sleep(0.5)
        end

    end
end
send(s) click to toggle source
# File lib/fantasy-irc/irc.rb, line 52
def send(s)
    # Send a message to the server
    if not @connected then
        raise "not connected to a server!"
    end

    # remove everything after a newline
    s.gsub!(/\n.*$/, "")
    puts "<-- #{s}"
    @data[:socket].puts "#{s}\n"
end