rhuidean 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/rhuidean.rb +1 -1
- data/lib/rhuidean/client.rb +26 -53
- data/lib/rhuidean/loggable.rb +59 -0
- data/lib/rhuidean/methods.rb +14 -0
- data/lib/rhuidean/stateful_client.rb +9 -9
- metadata +4 -3
data/lib/rhuidean.rb
CHANGED
data/lib/rhuidean/client.rb
CHANGED
|
@@ -8,15 +8,19 @@
|
|
|
8
8
|
# Import required Ruby modules
|
|
9
9
|
%w(logger socket).each { |m| require m }
|
|
10
10
|
|
|
11
|
+
# Import required application modules
|
|
12
|
+
%w(loggable).each { |m| require 'rhuidean/' + m }
|
|
13
|
+
|
|
11
14
|
module IRC
|
|
12
15
|
|
|
13
16
|
# The IRC::Client class acts as an abstract interface to the IRC protocol.
|
|
14
17
|
class Client
|
|
15
18
|
include Rhuidean # Version info and such
|
|
19
|
+
include Loggable # Magic logging stuff
|
|
16
20
|
|
|
17
21
|
##
|
|
18
22
|
# instance attributes
|
|
19
|
-
attr_accessor :server, :port, :password, :
|
|
23
|
+
attr_accessor :server, :port, :password, :thread,
|
|
20
24
|
:nickname, :username, :realname, :bind_to
|
|
21
25
|
|
|
22
26
|
# Our TCPSocket.
|
|
@@ -40,7 +44,7 @@ class Client
|
|
|
40
44
|
# c.bind_to = '10.0.1.20'
|
|
41
45
|
#
|
|
42
46
|
# c.logger = Logger.new($stderr)
|
|
43
|
-
# c.
|
|
47
|
+
# c.log_level = :debug
|
|
44
48
|
# end
|
|
45
49
|
#
|
|
46
50
|
# client.thread = Thread.new { client.io_loop }
|
|
@@ -65,9 +69,15 @@ class Client
|
|
|
65
69
|
# Our event queue.
|
|
66
70
|
@eventq = EventQueue.new
|
|
67
71
|
|
|
72
|
+
# Local IP to bind to
|
|
73
|
+
@bind_to = nil
|
|
74
|
+
|
|
75
|
+
# Password to login to the server
|
|
76
|
+
@password = nil
|
|
77
|
+
|
|
68
78
|
# Our Logger object.
|
|
69
|
-
@logger
|
|
70
|
-
|
|
79
|
+
@logger = Logger.new($stderr)
|
|
80
|
+
self.log_level = :info
|
|
71
81
|
|
|
72
82
|
# If we have a block let it set up our instance attributes.
|
|
73
83
|
yield(self) if block_given?
|
|
@@ -80,7 +90,7 @@ class Client
|
|
|
80
90
|
on(:dead) { self.dead = true }
|
|
81
91
|
|
|
82
92
|
on(:exit) do |from|
|
|
83
|
-
log("exiting via #{from}...")
|
|
93
|
+
log(:fatal, "exiting via #{from}...")
|
|
84
94
|
Thread.exit
|
|
85
95
|
end
|
|
86
96
|
|
|
@@ -108,8 +118,14 @@ class Client
|
|
|
108
118
|
# returns:: +self+
|
|
109
119
|
#
|
|
110
120
|
def set_default_handlers
|
|
121
|
+
# Append random numbers if our nick is in use
|
|
122
|
+
on(Numeric::ERR_NICKNAMEINUSE) do |m|
|
|
123
|
+
@nickname = m.params[0] + rand(100).to_s
|
|
124
|
+
nick(@nickname)
|
|
125
|
+
end
|
|
126
|
+
|
|
111
127
|
# Consider ourselves connected on 001
|
|
112
|
-
on(Numeric::RPL_WELCOME) { log("connected to #@server:#@port") }
|
|
128
|
+
on(Numeric::RPL_WELCOME) { log(:info, "connected to #@server:#@port") }
|
|
113
129
|
|
|
114
130
|
# Track our nickname...
|
|
115
131
|
on(:NICK) { |m| @nickname = m.target if m.origin_nick == @nickname }
|
|
@@ -162,7 +178,7 @@ class Client
|
|
|
162
178
|
#
|
|
163
179
|
def dead=(bool)
|
|
164
180
|
if bool == true
|
|
165
|
-
log("lost connection to #@server:#@port")
|
|
181
|
+
log(:info, "lost connection to #@server:#@port")
|
|
166
182
|
@dead = Time.now.to_i
|
|
167
183
|
@socket = nil
|
|
168
184
|
@connected = false
|
|
@@ -217,7 +233,7 @@ class Client
|
|
|
217
233
|
# Use shift because we need it to fall off immediately.
|
|
218
234
|
while line = @sendq.shift
|
|
219
235
|
line += "\r\n"
|
|
220
|
-
debug
|
|
236
|
+
log(:debug, line)
|
|
221
237
|
@socket.write(line)
|
|
222
238
|
end
|
|
223
239
|
rescue Errno::EAGAIN
|
|
@@ -265,7 +281,7 @@ class Client
|
|
|
265
281
|
@recvq.each do |line|
|
|
266
282
|
line.chomp!
|
|
267
283
|
|
|
268
|
-
debug
|
|
284
|
+
log(:debug, line)
|
|
269
285
|
|
|
270
286
|
m = IRC_RE.match(line)
|
|
271
287
|
|
|
@@ -291,53 +307,10 @@ class Client
|
|
|
291
307
|
self
|
|
292
308
|
end
|
|
293
309
|
|
|
294
|
-
#
|
|
295
|
-
# Logs a regular message.
|
|
296
|
-
# ---
|
|
297
|
-
# message:: the string to log
|
|
298
|
-
# returns:: +self+
|
|
299
|
-
#
|
|
300
|
-
def log(message)
|
|
301
|
-
@logger.info(caller[0].split('/')[-1]) { message } if @logger
|
|
302
|
-
end
|
|
303
|
-
|
|
304
|
-
#
|
|
305
|
-
# Logs a debug message.
|
|
306
|
-
# ---
|
|
307
|
-
# message:: the string to log
|
|
308
|
-
# returns:: +self+
|
|
309
|
-
#
|
|
310
|
-
def debug(message)
|
|
311
|
-
return unless @logger
|
|
312
|
-
|
|
313
|
-
@logger.debug(caller[0].split('/')[-1]) { message } if @debug
|
|
314
|
-
end
|
|
315
|
-
|
|
316
310
|
######
|
|
317
311
|
public
|
|
318
312
|
######
|
|
319
313
|
|
|
320
|
-
#
|
|
321
|
-
# Sets the logging object to use.
|
|
322
|
-
# If it quacks like a Logger object, it should work.
|
|
323
|
-
# ---
|
|
324
|
-
# logger:: the Logger to use
|
|
325
|
-
# returns:: +self+
|
|
326
|
-
#
|
|
327
|
-
def logger=(logger)
|
|
328
|
-
@logger = logger
|
|
329
|
-
|
|
330
|
-
# Set to false/nil to disable logging...
|
|
331
|
-
return unless @logger
|
|
332
|
-
|
|
333
|
-
@logger.progname = 'irc'
|
|
334
|
-
@logger.datetime_format = '%b %d %H:%M:%S '
|
|
335
|
-
|
|
336
|
-
# We only have 'logging' and 'debugging', so just set the
|
|
337
|
-
# object to show all levels. I might change this someday.
|
|
338
|
-
@logger.level = Logger::DEBUG
|
|
339
|
-
end
|
|
340
|
-
|
|
341
314
|
#
|
|
342
315
|
# Registers Event handlers with our EventQueue.
|
|
343
316
|
# ---
|
|
@@ -424,7 +397,7 @@ class Client
|
|
|
424
397
|
def connect
|
|
425
398
|
verify_attributes
|
|
426
399
|
|
|
427
|
-
log("connecting to #@server:#@port")
|
|
400
|
+
log(:info, "connecting to #@server:#@port")
|
|
428
401
|
|
|
429
402
|
begin
|
|
430
403
|
@socket = TCPSocket.new(@server, @port, @bind_to)
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
#
|
|
2
|
+
# rhuidean: a small, lightweight IRC client library
|
|
3
|
+
# lib/rhuidean/loggable.rb: a mixin for easy logging
|
|
4
|
+
#
|
|
5
|
+
# Copyright (c) 2003-2010 Eric Will <rakaur@malkier.net>
|
|
6
|
+
#
|
|
7
|
+
# encoding: utf-8
|
|
8
|
+
|
|
9
|
+
module Loggable
|
|
10
|
+
##
|
|
11
|
+
# Logs a regular message.
|
|
12
|
+
# ---
|
|
13
|
+
# message:: the string to log
|
|
14
|
+
# returns:: +self+
|
|
15
|
+
#
|
|
16
|
+
def log(level, message)
|
|
17
|
+
return unless level.to_s =~ /(fatal|error|warning|info|debug)/
|
|
18
|
+
|
|
19
|
+
@logger.send(level, caller[0].split('/')[-1]) { message } if @logger
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
##
|
|
23
|
+
# Sets the logging object to use.
|
|
24
|
+
# If it quacks like a Logger object, it should work.
|
|
25
|
+
# ---
|
|
26
|
+
# logger:: the Logger to use
|
|
27
|
+
# returns:: +self+
|
|
28
|
+
#
|
|
29
|
+
def logger=(logger)
|
|
30
|
+
logger.level = @logger.level if @logger and logger
|
|
31
|
+
|
|
32
|
+
@logger = logger
|
|
33
|
+
|
|
34
|
+
# Set to false/nil to disable logging...
|
|
35
|
+
return unless @logger
|
|
36
|
+
|
|
37
|
+
@logger.datetime_format = '%m/%d %H:%M:%S '
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def log_level=(level)
|
|
41
|
+
case level
|
|
42
|
+
when :none
|
|
43
|
+
@logger = nil
|
|
44
|
+
when :fatal
|
|
45
|
+
@logger.level = Logger::FATAL
|
|
46
|
+
when :error
|
|
47
|
+
@logger.level = Logger::ERROR
|
|
48
|
+
when :warning
|
|
49
|
+
@logger.level = Logger::WARN
|
|
50
|
+
when :info
|
|
51
|
+
@logger.level = Logger::INFO
|
|
52
|
+
when :debug
|
|
53
|
+
@logger.level = Logger::DEBUG
|
|
54
|
+
else
|
|
55
|
+
@logger.level = Logger::WARN
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end # module Loggable
|
|
59
|
+
|
data/lib/rhuidean/methods.rb
CHANGED
|
@@ -43,11 +43,25 @@ class Client
|
|
|
43
43
|
@sendq << "PRIVMSG #{to} :#{message}"
|
|
44
44
|
end
|
|
45
45
|
|
|
46
|
+
# Sends a CTCP
|
|
47
|
+
def ctcp(to, type, params = nil)
|
|
48
|
+
if params
|
|
49
|
+
@sendq << "PRIVMSG #{to} :\1#{type} #{params}\1"
|
|
50
|
+
else
|
|
51
|
+
@sendq << "PRIVMSG #{to} :\1#{type}\1"
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
46
55
|
# Sends an IRC NOTICE command.
|
|
47
56
|
def notice(to, message)
|
|
48
57
|
@sendq << "NOTICE #{to} :#{message}"
|
|
49
58
|
end
|
|
50
59
|
|
|
60
|
+
# Sends a CTCP reply
|
|
61
|
+
def ctcp_reply(to, type, params = '')
|
|
62
|
+
@sendq << "NOTICE #{to} :\1#{type} #{params}\1"
|
|
63
|
+
end
|
|
64
|
+
|
|
51
65
|
# Sends an IRC JOIN command.
|
|
52
66
|
def join(channel, key = '')
|
|
53
67
|
@sendq << "JOIN #{channel} #{key}"
|
|
@@ -179,7 +179,7 @@ class StatefulClient < Client
|
|
|
179
179
|
@users[user.nickname] ||= user
|
|
180
180
|
|
|
181
181
|
@channels[m.target].add_user(user)
|
|
182
|
-
|
|
182
|
+
log(:info, "join: #{user} -> #{m.target}")
|
|
183
183
|
end
|
|
184
184
|
end
|
|
185
185
|
|
|
@@ -196,12 +196,12 @@ class StatefulClient < Client
|
|
|
196
196
|
|
|
197
197
|
@channels.delete(chan.name)
|
|
198
198
|
|
|
199
|
-
|
|
199
|
+
log(:info, "parted: #{chan.name}")
|
|
200
200
|
else
|
|
201
201
|
user = @users[m.origin_nick]
|
|
202
202
|
|
|
203
203
|
@channels[m.target].delete_user(user)
|
|
204
|
-
|
|
204
|
+
log(:info, "part: #{user.nickname} -> #{m.origin_nick}")
|
|
205
205
|
|
|
206
206
|
delete_user(user) if user.channels.empty?
|
|
207
207
|
end
|
|
@@ -222,7 +222,7 @@ class StatefulClient < Client
|
|
|
222
222
|
channel.users.delete(m.origin_nick)
|
|
223
223
|
end
|
|
224
224
|
|
|
225
|
-
|
|
225
|
+
log(:info, "nick: #{m.origin_nick} -> #{m.target}")
|
|
226
226
|
end
|
|
227
227
|
|
|
228
228
|
def do_kick(m)
|
|
@@ -238,12 +238,12 @@ class StatefulClient < Client
|
|
|
238
238
|
|
|
239
239
|
@channels.delete(chan.name)
|
|
240
240
|
|
|
241
|
-
|
|
241
|
+
log(:info, "kicked: #{chan.name}")
|
|
242
242
|
else
|
|
243
243
|
user = @users[m.params[0]]
|
|
244
244
|
|
|
245
245
|
@channels[m.target].delete_user(user)
|
|
246
|
-
|
|
246
|
+
log(:info, "kick: #{user.nickname} -> #{m.origin_nick}")
|
|
247
247
|
|
|
248
248
|
delete_user(user) if user.channels.empty?
|
|
249
249
|
end
|
|
@@ -258,7 +258,7 @@ class StatefulClient < Client
|
|
|
258
258
|
user.channels.each { |name, chan| chan.delete_user(user) }
|
|
259
259
|
|
|
260
260
|
delete_user(user)
|
|
261
|
-
|
|
261
|
+
log(:info, "quit: #{user.nickname}")
|
|
262
262
|
end
|
|
263
263
|
end
|
|
264
264
|
|
|
@@ -273,7 +273,7 @@ class StatefulClient < Client
|
|
|
273
273
|
names[0] = names[0][1..-1] # Get rid of leading ':'
|
|
274
274
|
modes = @status_modes.keys
|
|
275
275
|
prefixes = @status_modes.values
|
|
276
|
-
name_re = /^([#{prefixes}])*(.+)/
|
|
276
|
+
name_re = /^([#{prefixes.join('')}])*(.+)/
|
|
277
277
|
|
|
278
278
|
names.each do |name|
|
|
279
279
|
m = name_re.match(name)
|
|
@@ -294,7 +294,7 @@ class StatefulClient < Client
|
|
|
294
294
|
end
|
|
295
295
|
|
|
296
296
|
chan.add_user(user)
|
|
297
|
-
debug
|
|
297
|
+
log(:debug, "names: #{user} -> #{chan}")
|
|
298
298
|
end
|
|
299
299
|
end
|
|
300
300
|
end
|
metadata
CHANGED
|
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
|
4
4
|
prerelease: false
|
|
5
5
|
segments:
|
|
6
6
|
- 1
|
|
7
|
+
- 1
|
|
7
8
|
- 0
|
|
8
|
-
|
|
9
|
-
version: 1.0.0
|
|
9
|
+
version: 1.1.0
|
|
10
10
|
platform: ruby
|
|
11
11
|
authors:
|
|
12
12
|
- Eric Will
|
|
@@ -14,7 +14,7 @@ autorequire:
|
|
|
14
14
|
bindir: bin
|
|
15
15
|
cert_chain: []
|
|
16
16
|
|
|
17
|
-
date: 2010-11-
|
|
17
|
+
date: 2010-11-11 00:00:00 -05:00
|
|
18
18
|
default_executable:
|
|
19
19
|
dependencies: []
|
|
20
20
|
|
|
@@ -38,6 +38,7 @@ files:
|
|
|
38
38
|
- lib/rhuidean/stateful_channel.rb
|
|
39
39
|
- lib/rhuidean/stateful_client.rb
|
|
40
40
|
- lib/rhuidean/stateful_user.rb
|
|
41
|
+
- lib/rhuidean/loggable.rb
|
|
41
42
|
- test/tc_client.rb
|
|
42
43
|
- test/ts_rhuidean.rb
|
|
43
44
|
has_rdoc: true
|