Class: Percy::IRC

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

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.configObject (readonly)

Returns the value of attribute config.



10
11
12
# File 'lib/percy/irc.rb', line 10

def config
  @config
end

.connectedObject

Returns the value of attribute connected.



11
12
13
# File 'lib/percy/irc.rb', line 11

def connected
  @connected
end

.traffic_loggerObject

Returns the value of attribute traffic_logger.



11
12
13
# File 'lib/percy/irc.rb', line 11

def traffic_logger
  @traffic_logger
end

Class Method Details

.action(recipient, message) ⇒ Object

perform an action



81
82
83
# File 'lib/percy/irc.rb', line 81

def self.action(recipient, message)
  self.raw "PRIVMSG #{recipient} :\001ACTION #{message}\001"
end

.channel_limit(channel) ⇒ Object

get the channel limit of a channel



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
# File 'lib/percy/irc.rb', line 192

def self.channel_limit(channel)
  actual_length = self.add_observer
  self.raw "MODE #{channel}"
  
  begin
    Timeout::timeout(10) do # try 10 seconds to retrieve l mode of <channel>
      start = actual_length
      ending = @temp_socket.length
      channel = Regexp.escape(channel)
      
      loop do
        for line in start..ending do
          if @temp_socket[line] =~ /^:\S+ 324 \S+ #{channel} .*l.* (\d+)/
            return $1.to_i
          end
        end
        
        sleep 0.25
        start = ending
        ending = @temp_socket.length
      end
    end
  rescue Timeout::Error
    return false
  ensure
    self.remove_observer
  end
end

.configure(&block) ⇒ Object



37
38
39
40
41
42
43
44
45
46
47
# File 'lib/percy/irc.rb', line 37

def self.configure(&block)
  unless @reloading
    block.call(@config)
    
    # logger
    if @config.logging
      @traffic_logger = PercyLogger.new(Pathname.new(PERCY_ROOT).join('logs').expand_path, 'traffic.log')
      @error_logger   = PercyLogger.new(Pathname.new(PERCY_ROOT).join('logs').expand_path, 'error.log')
    end
  end
end

.connectObject

connect!



282
283
284
285
286
287
288
289
290
291
# File 'lib/percy/irc.rb', line 282

def self.connect
  unless @reloading
    @traffic_logger.info('-- Starting Percy') if @traffic_logger
    puts "#{Time.now.strftime('%d.%m.%Y %H:%M:%S')} -- Starting Percy"
    
    EventMachine::run do
      @connection = EventMachine::connect(@config.server, @config.port, Connection)
    end
  end
end

.is_online(nick) ⇒ Object

check whether an user is online



222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
# File 'lib/percy/irc.rb', line 222

def self.is_online(nick)
  actual_length = self.add_observer
  self.raw "WHOIS #{nick}"
  
  begin
    Timeout::timeout(10) do
      start = actual_length
      ending = @temp_socket.length
      nick = Regexp.escape(nick)
      
      loop do
        for line in start..ending do
          if @temp_socket[line] =~ /^:\S+ 311 \S+ (#{nick}) /i
            return $1
          elsif @temp_socket[line] =~ /^:\S+ 401 \S+ #{nick} /i
            return false
          end
        end
        
        sleep 0.25
        start = ending
        ending = @temp_socket.length
      end
    end
  rescue Timeout::Error
    return false
  ensure
    self.remove_observer
  end
end

.join(channel, password = nil) ⇒ Object

joining a channel



91
92
93
94
95
96
97
# File 'lib/percy/irc.rb', line 91

def self.join(channel, password = nil)
  if password
    self.raw "JOIN #{channel} #{password}"
  else
    self.raw "JOIN #{channel}"
  end
end

.kick(channel, user, reason) ⇒ Object

kick a user



72
73
74
75
76
77
78
# File 'lib/percy/irc.rb', line 72

def self.kick(channel, user, reason)
  if reason
    self.raw "KICK #{channel} #{user} :#{reason}"
  else
    self.raw "KICK #{channel} #{user}"
  end
end

.message(recipient, message) ⇒ Object

send a message



57
58
59
# File 'lib/percy/irc.rb', line 57

def self.message(recipient, message)
  self.raw "PRIVMSG #{recipient} :#{message}"
end

.mode(recipient, option) ⇒ Object

set a mode



67
68
69
# File 'lib/percy/irc.rb', line 67

def self.mode(recipient, option)
  self.raw "MODE #{recipient} #{option}"
end

.nickObject



119
120
121
# File 'lib/percy/irc.rb', line 119

def self.nick
  @config.nick
end

.notice(recipient, message) ⇒ Object

send a notice



62
63
64
# File 'lib/percy/irc.rb', line 62

def self.notice(recipient, message)
  self.raw "NOTICE #{recipient} :#{message}"
end

.on(type = [:channel], match = //, &block) ⇒ Object

on method



254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
# File 'lib/percy/irc.rb', line 254

def self.on(type = [:channel], match = //, &block)
  if (type.is_a?(Symbol) || type.is_a?(String))
    type = [type]
  end
  
  if type.is_a? Array
    type.each do |t|
      unless @listened_types.include?(t) || t =~ /^\d\d\d$/
        raise ArgumentError, "#{t} is not a supported type"
      end
      
      if @events[t].empty?
        @events[t] = [] # @events' default value is [], but it's not possible to add elements to it (weird!)
      end
      
      case t
      when :channel
        @events[t] << {:match => match, :proc => block}
      when :query
        @events[t] << {:match => match, :proc => block}
      else
        @events[t] << block
      end
    end
  end
end

.part(channel, message) ⇒ Object

parting a channel



100
101
102
103
104
105
106
# File 'lib/percy/irc.rb', line 100

def self.part(channel, message)
  if msg
    self.raw "PART #{channel} :#{message}"
  else
    self.raw 'PART'
  end
end

.quit(message = nil) ⇒ Object

quitting



109
110
111
112
113
114
115
116
117
# File 'lib/percy/irc.rb', line 109

def self.quit(message = nil)
  if message
    self.raw "QUIT :#{message}"
  else
    self.raw 'QUIT'
  end
  
  @config.reconnect = false # so Percy does not reconnect after the socket has been closed
end

.raw(message) ⇒ Object

raw IRC messages



50
51
52
53
54
# File 'lib/percy/irc.rb', line 50

def self.raw(message)
  @connection.send_data "#{message}\r\n"
  @traffic_logger.info(">> #{message}") if @traffic_logger
  puts "#{Time.now.strftime('%d.%m.%Y %H:%M:%S')} >> #{message}" if @config.verbose
end

.reloadObject



293
294
295
296
297
298
# File 'lib/percy/irc.rb', line 293

def self.reload
  @reloading = true
  @events = Hash.new []
  load $0
  @reloading = false
end

.reloading?Boolean

Returns:

  • (Boolean)


300
301
302
# File 'lib/percy/irc.rb', line 300

def self.reloading?
  @reloading
end

.topic(channel, topic) ⇒ Object

set a topic



86
87
88
# File 'lib/percy/irc.rb', line 86

def self.topic(channel, topic)
  self.raw "TOPIC #{channel} :#{topic}"
end

.users_on(channel) ⇒ Object

returns all users on a specific channel as array: [‘Foo’, ‘bar’, ‘The_Librarian’]



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
# File 'lib/percy/irc.rb', line 124

def self.users_on(channel)
  actual_length = self.add_observer
  self.raw "NAMES #{channel}"
  channel = Regexp.escape(channel)
  
  begin
    Timeout::timeout(30) do # try 30 seconds to retrieve the users of <channel>
      start = actual_length
      ending = @temp_socket.length
      users = []
      
      loop do
        for line in start..ending do
          case @temp_socket[line]
          when /^:\S+ 353 .+ #{channel} :/i
            users << $'.split(' ')
          when /^:\S+ 366 .+ #{channel}/i
            return users.flatten.uniq.map { |element| element.gsub(/[!@%+]/, '') } # removing all modes
          end
        end
        
        sleep 0.25
        start = ending
        ending = @temp_socket.length
      end
    end
  rescue Timeout::Error
    return []
  ensure
    self.remove_observer
  end
end

.users_with_status_on(channel) ⇒ Object

returns all users on a specific channel as array (with status): [‘@Foo’, ‘+bar’, ‘The_Librarian’, ‘!Frank’]



158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/percy/irc.rb', line 158

def self.users_with_status_on(channel)
  actual_length = self.add_observer
  self.raw "NAMES #{channel}"
  channel = Regexp.escape(channel)
  
  begin
    Timeout::timeout(30) do # try 30 seconds to retrieve the users of <channel>
      start = actual_length
      ending = @temp_socket.length
      users = []
      
      loop do
        for line in start..ending do
          case @temp_socket[line]
          when /^:\S+ 353 .+ #{channel} :/i
            users << $'.split(' ')
          when /^:\S+ 366 .+ #{channel}/i
            return users.flatten.uniq
          end
        end
        
        sleep 0.25
        start = ending
        ending = @temp_socket.length
      end
    end
  rescue Timeout::Error
    return []
  ensure
    self.remove_observer
  end
end