Class: Fantasy::IRC

Inherits:
Object
  • Object
show all
Defined in:
lib/fantasy-irc/irc.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ IRC

Returns a new instance of IRC.



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 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

Instance Attribute Details

#connectedObject (readonly)

Returns the value of attribute connected.



8
9
10
# File 'lib/fantasy-irc/irc.rb', line 8

def connected
  @connected
end

#eventsObject (readonly)

Returns the value of attribute events.



7
8
9
# File 'lib/fantasy-irc/irc.rb', line 7

def events
  @events
end

#loggedinObject (readonly)

Returns the value of attribute loggedin.



8
9
10
# File 'lib/fantasy-irc/irc.rb', line 8

def loggedin
  @loggedin
end

#pluginsObject (readonly)

Returns the value of attribute plugins.



7
8
9
# File 'lib/fantasy-irc/irc.rb', line 7

def plugins
  @plugins
end

#roomsObject (readonly)

Returns the value of attribute rooms.



7
8
9
# File 'lib/fantasy-irc/irc.rb', line 7

def rooms
  @rooms
end

#sessionObject (readonly)

Returns the value of attribute session.



8
9
10
# File 'lib/fantasy-irc/irc.rb', line 8

def session
  @session
end

#startedObject (readonly)

Returns the value of attribute started.



8
9
10
# File 'lib/fantasy-irc/irc.rb', line 8

def started
  @started
end

#usersObject (readonly)

Returns the value of attribute users.



7
8
9
# File 'lib/fantasy-irc/irc.rb', line 7

def users
  @users
end

Instance Method Details

#cleanupObject



86
87
88
89
# File 'lib/fantasy-irc/irc.rb', line 86

def cleanup
    puts "[!][Cleanup] Closing socket."
    @data[:socket].close()
end

#connect(data) ⇒ Object



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/fantasy-irc/irc.rb', line 61

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) ⇒ Object



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/fantasy-irc/irc.rb', line 29

def  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) ⇒ Object



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/fantasy-irc/irc.rb', line 91

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 = self.rooms.by_name(tok[2][1,tok[2].length])
            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 |room|
                room.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

#runObject



181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
# File 'lib/fantasy-irc/irc.rb', line 181

def run
    if @running.nonzero? then
        return false
    end

    @running = Time.now.to_i
    last_tick = @running
    last_ping = @running
    last_session_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) ⇒ Object



52
53
54
55
56
57
58
59
# 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
    puts "<-- #{s}"
    @data[:socket].puts "#{s}\n"
end