net-irc 0.0.8 → 0.0.9
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog +9 -0
- data/Rakefile +10 -19
- data/examples/2ch.rb +225 -0
- data/examples/2ig.rb +267 -0
- data/examples/echo_bot.rb +1 -1
- data/examples/gmail.rb +2 -2
- data/examples/hatena-star-stream.rb +10 -4
- data/examples/hig.rb +9 -4
- data/examples/iig.rb +3 -3
- data/examples/ircd.rb +1 -1
- data/examples/lig.rb +551 -0
- data/examples/lingr.rb +327 -0
- data/examples/mixi.rb +2 -2
- data/examples/sig.rb +2 -2
- data/examples/tig.rb +552 -386
- data/examples/wig.rb +11 -4
- data/lib/net/irc.rb +1 -1
- data/lib/net/irc/server.rb +1 -0
- data/spec/channel_manager_spec.rb +4 -1
- data/spec/net-irc_spec.rb +4 -2
- metadata +12 -11
data/ChangeLog
CHANGED
@@ -1,7 +1,16 @@
|
|
1
|
+
2009-10-11 SATOH Hiroh <cho45@lowreal.net>
|
2
|
+
|
3
|
+
* [new]
|
4
|
+
Implemented Server#sessions which returns all sessions connected to
|
5
|
+
the server.
|
6
|
+
* Released 0.0.9
|
7
|
+
|
1
8
|
2009-08-08 SATOH Hiroh <cho45@lowreal.net>
|
2
9
|
|
3
10
|
* [bug]:
|
4
11
|
Fixed to work on ruby1.9.1 (now can send iso-2022-jp)
|
12
|
+
* [new]
|
13
|
+
Implemented Message#ctcps returns embedded all ctcp messages (drry).
|
5
14
|
* Released 0.0.8
|
6
15
|
|
7
16
|
2009-02-19 SATOH Hiroh <cho45@lowreal.net>
|
data/Rakefile
CHANGED
@@ -5,7 +5,6 @@ require 'rake/clean'
|
|
5
5
|
require 'rake/packagetask'
|
6
6
|
require 'rake/gempackagetask'
|
7
7
|
require 'rake/rdoctask'
|
8
|
-
require 'rake/contrib/rubyforgepublisher'
|
9
8
|
require 'rake/contrib/sshpublisher'
|
10
9
|
require 'fileutils'
|
11
10
|
require 'spec/rake/spectask'
|
@@ -19,8 +18,7 @@ NAME = "net-irc"
|
|
19
18
|
AUTHOR = "cho45"
|
20
19
|
EMAIL = "cho45@lowreal.net"
|
21
20
|
DESCRIPTION = "library for implementing IRC server and client"
|
22
|
-
|
23
|
-
HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
|
21
|
+
HOMEPATH = "http://cho45.stfuawsc.com/net-irc/"
|
24
22
|
BIN_FILES = %w( )
|
25
23
|
VERS = Net::IRC::VERSION.dup
|
26
24
|
|
@@ -57,7 +55,6 @@ spec = Gem::Specification.new do |s|
|
|
57
55
|
s.email = EMAIL
|
58
56
|
s.homepage = HOMEPATH
|
59
57
|
s.executables = BIN_FILES
|
60
|
-
s.rubyforge_project = RUBYFORGE_PROJECT
|
61
58
|
s.bindir = "bin"
|
62
59
|
s.require_path = "lib"
|
63
60
|
s.autorequire = ""
|
@@ -89,6 +86,10 @@ task :uninstall => [:clean] do
|
|
89
86
|
sh %{sudo gem uninstall #{NAME}}
|
90
87
|
end
|
91
88
|
|
89
|
+
task :upload_doc => [:rdoc] do
|
90
|
+
sh %{rsync --update -avptr html/ lowreal@cho45.stfuawsc.com:/virtual/lowreal/public_html/cho45.stfuawsc.com/net-irc}
|
91
|
+
end
|
92
|
+
|
92
93
|
|
93
94
|
Rake::RDocTask.new do |rdoc|
|
94
95
|
rdoc.rdoc_dir = 'html'
|
@@ -104,24 +105,14 @@ Rake::RDocTask.new do |rdoc|
|
|
104
105
|
end
|
105
106
|
end
|
106
107
|
|
107
|
-
desc "Publish to RubyForge"
|
108
|
-
task :rubyforge => [:rdoc, :package] do
|
109
|
-
require 'rubyforge'
|
110
|
-
@local_dir = "html"
|
111
|
-
@host = "cho45@rubyforge.org"
|
112
|
-
@remote_dir = "/var/www/gforge-projects/#{RUBYFORGE_PROJECT}/#{NAME}"
|
113
|
-
sh %{rsync -r --delete --verbose #{@local_dir}/ #{@host}:#{@remote_dir}}
|
114
|
-
end
|
115
|
-
|
116
108
|
Rake::ShipitTask.new do |s|
|
117
|
-
s.Step.new {
|
118
|
-
system("svn", "up")
|
119
|
-
}.and {}
|
120
109
|
s.ChangeVersion "lib/net/irc.rb", "VERSION"
|
121
110
|
s.Commit
|
122
|
-
s.Task :clean, :package
|
123
|
-
s.
|
111
|
+
s.Task :clean, :package, :upload_doc
|
112
|
+
s.Step.new {
|
113
|
+
}.and {
|
114
|
+
system("gem", "push", "pkg/net-irc-#{VERS}.gem")
|
115
|
+
}
|
124
116
|
s.Tag
|
125
117
|
s.Twitter
|
126
|
-
s.Task :rubyforge
|
127
118
|
end
|
data/examples/2ch.rb
ADDED
@@ -0,0 +1,225 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# vim:encoding=UTF-8:
|
3
|
+
$KCODE = "u" if RUBY_VERSION < "1.9" # json use this
|
4
|
+
|
5
|
+
require 'uri'
|
6
|
+
require 'net/http'
|
7
|
+
require 'stringio'
|
8
|
+
require 'zlib'
|
9
|
+
require 'nkf'
|
10
|
+
|
11
|
+
class ThreadData
|
12
|
+
class UnknownThread < StandardError; end
|
13
|
+
|
14
|
+
attr_accessor :uri
|
15
|
+
attr_accessor :last_modified, :size
|
16
|
+
|
17
|
+
Line = Struct.new(:n, :name, :mail, :misc, :body, :opts, :id) do
|
18
|
+
def aa?
|
19
|
+
body = self.body
|
20
|
+
return false if body.count("\n") < 3
|
21
|
+
|
22
|
+
significants = body.scan(/[>\n0-9a-z0-9A-Za-zA-Zぁ-んァ-ン一-龠]/u).size.to_f
|
23
|
+
body_length = body.scan(/./u).size
|
24
|
+
is_aa = 1 - significants / body_length
|
25
|
+
|
26
|
+
is_aa > 0.6
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def initialize(thread_uri)
|
31
|
+
@uri = URI(thread_uri)
|
32
|
+
_, _, _, @board, @num, = *@uri.path.split('/')
|
33
|
+
@dat = []
|
34
|
+
end
|
35
|
+
|
36
|
+
def length
|
37
|
+
@dat.length
|
38
|
+
end
|
39
|
+
|
40
|
+
def subject
|
41
|
+
retrieve(true) if @dat.size.zero?
|
42
|
+
self[1].opts || ""
|
43
|
+
end
|
44
|
+
|
45
|
+
def [](n)
|
46
|
+
l = @dat[n - 1]
|
47
|
+
return nil unless l
|
48
|
+
name, mail, misc, body, opts = * l.split(/<>/)
|
49
|
+
id = misc[/ID:([^\s]+)/, 1]
|
50
|
+
|
51
|
+
body.gsub!(/<br>/, "\n")
|
52
|
+
body.gsub!(/<[^>]+>/, "")
|
53
|
+
body.gsub!(/^\s+|\s+$/, "")
|
54
|
+
body.gsub!(/&(gt|lt|amp|nbsp);/) {|s|
|
55
|
+
{ 'gt' => ">", 'lt' => "<", 'amp' => "&", 'nbsp' => " " }[$1]
|
56
|
+
}
|
57
|
+
|
58
|
+
Line.new(n, name, mail, misc, body, opts, id)
|
59
|
+
end
|
60
|
+
|
61
|
+
def dat
|
62
|
+
@num
|
63
|
+
end
|
64
|
+
|
65
|
+
def retrieve(force=false)
|
66
|
+
@dat = [] if @force
|
67
|
+
|
68
|
+
res = Net::HTTP.start(@uri.host, @uri.port) do |http|
|
69
|
+
req = Net::HTTP::Get.new('/%s/dat/%d.dat' % [@board, @num])
|
70
|
+
req['User-Agent'] = 'Monazilla/1.00 (2ig.rb/0.0e)'
|
71
|
+
req['Accept-Encoding'] = 'gzip' unless @size
|
72
|
+
unless force
|
73
|
+
req['If-Modified-Since'] = @last_modified if @last_modified
|
74
|
+
req['Range'] = "bytes=%d-" % @size if @size
|
75
|
+
end
|
76
|
+
|
77
|
+
http.request(req)
|
78
|
+
end
|
79
|
+
|
80
|
+
ret = nil
|
81
|
+
case res.code.to_i
|
82
|
+
when 200, 206
|
83
|
+
body = res.body
|
84
|
+
if res['Content-Encoding'] == 'gzip'
|
85
|
+
body = StringIO.open(body, 'rb') {|io| Zlib::GzipReader.new(io).read }
|
86
|
+
end
|
87
|
+
|
88
|
+
@last_modified = res['Last-Modified']
|
89
|
+
if res.code == '206'
|
90
|
+
@size += body.size
|
91
|
+
else
|
92
|
+
@size = body.size
|
93
|
+
end
|
94
|
+
|
95
|
+
body = NKF.nkf('-w', body)
|
96
|
+
|
97
|
+
curr = @dat.size + 1
|
98
|
+
@dat.concat(body.split(/\n/))
|
99
|
+
last = @dat.size
|
100
|
+
|
101
|
+
(curr..last).map {|n|
|
102
|
+
self[n]
|
103
|
+
}
|
104
|
+
when 416 # たぶん削除が発生
|
105
|
+
p ['416']
|
106
|
+
retrieve(true)
|
107
|
+
[]
|
108
|
+
when 304 # Not modified
|
109
|
+
[]
|
110
|
+
when 302 # dat 落ち
|
111
|
+
p ['302', res['Location']]
|
112
|
+
raise UnknownThread
|
113
|
+
else
|
114
|
+
p ['Unknown Status:', res.code]
|
115
|
+
[]
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def canonicalize_subject(subject)
|
120
|
+
subject.gsub(/[A-Za-z0-9]/u) {|c|
|
121
|
+
c.unpack("U*").map {|i| i - 65248 }.pack("U*")
|
122
|
+
}
|
123
|
+
end
|
124
|
+
|
125
|
+
def guess_next_thread
|
126
|
+
res = Net::HTTP.start(@uri.host, @uri.port) do |http|
|
127
|
+
req = Net::HTTP::Get.new('/%s/subject.txt' % @board)
|
128
|
+
req['User-Agent'] = 'Monazilla/1.00 (2ig.rb/0.0e)'
|
129
|
+
http.request(req)
|
130
|
+
end
|
131
|
+
|
132
|
+
recent_posted_threads = (900..999).inject({}) {|r,i|
|
133
|
+
line = self[i]
|
134
|
+
line.body.scan(%r|ttp://#{@uri.host}/test/read.cgi/[^/]+/\d+/|).each do |uri|
|
135
|
+
r["h#{uri}"] = i
|
136
|
+
end if line
|
137
|
+
r
|
138
|
+
}
|
139
|
+
|
140
|
+
current_subject = canonicalize_subject(self.subject)
|
141
|
+
current_thread_rev = current_subject.scan(/\d+/).map {|d| d.to_i }
|
142
|
+
current = current_subject.scan(/./u)
|
143
|
+
|
144
|
+
body = NKF.nkf('-w', res.body)
|
145
|
+
threads = body.split(/\n/).map {|l|
|
146
|
+
dat, rest = *l.split(/<>/)
|
147
|
+
dat.sub!(/\.dat$/, "")
|
148
|
+
|
149
|
+
uri = "http://#{@uri.host}/test/read.cgi/#{@board}/#{dat}/"
|
150
|
+
|
151
|
+
subject, n = */(.+?) \((\d+)\)/.match(rest).captures
|
152
|
+
canonical_subject = canonicalize_subject(subject)
|
153
|
+
thread_rev = canonical_subject[/\d+/].to_i
|
154
|
+
|
155
|
+
distance = (dat == self.dat) ? Float::MAX :
|
156
|
+
(subject == self.subject) ? 0 :
|
157
|
+
levenshtein(canonical_subject.scan(/./u), current)
|
158
|
+
continuous_num = current_thread_rev.find {|rev| rev == thread_rev - 1 }
|
159
|
+
appear_recent = recent_posted_threads[uri]
|
160
|
+
|
161
|
+
score = distance
|
162
|
+
score -= 10 if continuous_num
|
163
|
+
score -= 10 if appear_recent
|
164
|
+
score += 10 if dat.to_i < self.dat.to_i
|
165
|
+
{
|
166
|
+
:uri => uri,
|
167
|
+
:dat => dat,
|
168
|
+
:subject => subject,
|
169
|
+
:distance => distance,
|
170
|
+
:continuous_num => continuous_num,
|
171
|
+
:appear_recent => appear_recent,
|
172
|
+
:score => score.to_f
|
173
|
+
}
|
174
|
+
}.sort_by {|o|
|
175
|
+
o[:score]
|
176
|
+
}
|
177
|
+
|
178
|
+
threads
|
179
|
+
end
|
180
|
+
|
181
|
+
def levenshtein(a, b)
|
182
|
+
case
|
183
|
+
when a.empty?
|
184
|
+
b.length
|
185
|
+
when b.empty?
|
186
|
+
a.length
|
187
|
+
when a == b
|
188
|
+
0
|
189
|
+
else
|
190
|
+
d = Array.new(a.length + 1) { |s|
|
191
|
+
Array.new(b.length + 1, 0)
|
192
|
+
}
|
193
|
+
|
194
|
+
(0..a.length).each do |i|
|
195
|
+
d[i][0] = i
|
196
|
+
end
|
197
|
+
|
198
|
+
(0..b.length).each do |j|
|
199
|
+
d[0][j] = j
|
200
|
+
end
|
201
|
+
|
202
|
+
(1..a.length).each do |i|
|
203
|
+
(1..b.length).each do |j|
|
204
|
+
cost = (a[i - 1] == b[j - 1]) ? 0 : 1
|
205
|
+
d[i][j] = [
|
206
|
+
d[i-1][j ] + 1,
|
207
|
+
d[i ][j-1] + 1,
|
208
|
+
d[i-1][j-1] + cost
|
209
|
+
].min
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
d[a.length][b.length]
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
if __FILE__ == $0
|
219
|
+
require 'pp'
|
220
|
+
thread = ThreadData.new(ARGV[0])
|
221
|
+
pp thread.guess_next_thread.reverse
|
222
|
+
|
223
|
+
p thread.subject
|
224
|
+
end
|
225
|
+
|
data/examples/2ig.rb
ADDED
@@ -0,0 +1,267 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# vim:encoding=UTF-8:
|
3
|
+
|
4
|
+
$LOAD_PATH << "lib"
|
5
|
+
$LOAD_PATH << "../lib"
|
6
|
+
|
7
|
+
$KCODE = "u" if RUBY_VERSION < "1.9" # json use this
|
8
|
+
|
9
|
+
require "rubygems"
|
10
|
+
require "net/irc"
|
11
|
+
require "logger"
|
12
|
+
require "pathname"
|
13
|
+
require "yaml"
|
14
|
+
require 'uri'
|
15
|
+
require 'net/http'
|
16
|
+
require 'nkf'
|
17
|
+
require 'stringio'
|
18
|
+
require 'zlib'
|
19
|
+
|
20
|
+
require "#{Pathname.new(__FILE__).parent.expand_path}/2ch.rb"
|
21
|
+
Net::HTTP.version_1_2
|
22
|
+
|
23
|
+
class NiChannelIrcGateway < Net::IRC::Server::Session
|
24
|
+
def server_name
|
25
|
+
"2ch"
|
26
|
+
end
|
27
|
+
|
28
|
+
def server_version
|
29
|
+
"0.0.0"
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
def initialize(*args)
|
34
|
+
super
|
35
|
+
@channels = {}
|
36
|
+
end
|
37
|
+
|
38
|
+
def on_disconnected
|
39
|
+
@channels.each do |chan, info|
|
40
|
+
begin
|
41
|
+
info[:observer].kill if info[:observer]
|
42
|
+
rescue
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def on_user(m)
|
48
|
+
super
|
49
|
+
@real, *@opts = @real.split(/\s+/)
|
50
|
+
@opts ||= []
|
51
|
+
end
|
52
|
+
|
53
|
+
def on_join(m)
|
54
|
+
channels = m.params.first.split(/,/)
|
55
|
+
channels.each do |channel|
|
56
|
+
@channels[channel] = {
|
57
|
+
:topic => "",
|
58
|
+
:dat => nil,
|
59
|
+
:interval => nil,
|
60
|
+
:observer => nil,
|
61
|
+
} unless @channels.key?(channel)
|
62
|
+
post @prefix, JOIN, channel
|
63
|
+
post nil, RPL_NAMREPLY, @prefix.nick, "=", channel, "@#{@prefix.nick}"
|
64
|
+
post nil, RPL_ENDOFNAMES, @prefix.nick, channel, "End of NAMES list"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def on_part(m)
|
69
|
+
channel = m.params[0]
|
70
|
+
if @channels.key?(channel)
|
71
|
+
info = @channels.delete(channel)
|
72
|
+
info[:observer].kill if info[:observer]
|
73
|
+
post @prefix, PART, channel
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def on_privmsg(m)
|
78
|
+
target, mesg = *m.params
|
79
|
+
m.ctcps.each {|ctcp| on_ctcp(target, ctcp) } if m.ctcp?
|
80
|
+
end
|
81
|
+
|
82
|
+
def on_ctcp(target, mesg)
|
83
|
+
type, mesg = mesg.split(" ", 2)
|
84
|
+
method = "on_ctcp_#{type.downcase}".to_sym
|
85
|
+
send(method, target, mesg) if respond_to? method, true
|
86
|
+
end
|
87
|
+
|
88
|
+
def on_ctcp_action(target, mesg)
|
89
|
+
command, *args = mesg.split(" ")
|
90
|
+
command.downcase!
|
91
|
+
|
92
|
+
case command
|
93
|
+
when 'next'
|
94
|
+
if @channels.key?(target)
|
95
|
+
guess_next_thread(target)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
rescue Exception => e
|
99
|
+
@log.error e.inspect
|
100
|
+
e.backtrace.each do |l|
|
101
|
+
@log.error "\t#{l}"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def on_topic(m)
|
106
|
+
channel, topic, = m.params
|
107
|
+
p m.params
|
108
|
+
if @channels.key?(channel)
|
109
|
+
info = @channels[channel]
|
110
|
+
|
111
|
+
unless topic
|
112
|
+
post nil, '332', channel, info[:topic]
|
113
|
+
return
|
114
|
+
end
|
115
|
+
|
116
|
+
uri, interval = *topic.split(/\s/)
|
117
|
+
interval = interval.to_i
|
118
|
+
|
119
|
+
post @prefix, TOPIC, channel, topic
|
120
|
+
|
121
|
+
case
|
122
|
+
when !info[:dat], uri != info[:dat].uri
|
123
|
+
post @prefix, NOTICE, channel, "Thread URL has been changed."
|
124
|
+
info[:dat] = ThreadData.new(uri)
|
125
|
+
create_observer(channel)
|
126
|
+
when info[:interval] != interval
|
127
|
+
post @prefix, NOTICE, channel, "Interval has been changed."
|
128
|
+
create_observer(channel)
|
129
|
+
end
|
130
|
+
info[:topic] = topic
|
131
|
+
info[:interval] = interval > 0 ? interval : 90
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def guess_next_thread(channel)
|
136
|
+
info = @channels[channel]
|
137
|
+
post server_name, NOTICE, channel, "Current Thread: #{info[:dat].subject}"
|
138
|
+
threads = info[:dat].guess_next_thread
|
139
|
+
threads.first(3).each do |t|
|
140
|
+
if t[:continuous_num] && t[:appear_recent]
|
141
|
+
post server_name, NOTICE, channel, "#{t[:uri]} \003%d#{t[:subject]}\017" % 10
|
142
|
+
else
|
143
|
+
post server_name, NOTICE, channel, "#{t[:uri]} #{t[:subject]}"
|
144
|
+
end
|
145
|
+
end
|
146
|
+
threads
|
147
|
+
end
|
148
|
+
|
149
|
+
def create_observer(channel)
|
150
|
+
info = @channels[channel]
|
151
|
+
info[:observer].kill if info[:observer]
|
152
|
+
|
153
|
+
@log.debug "create_observer %s, interval %d" % [channel, info[:interval]]
|
154
|
+
info[:observer] = Thread.start(info, channel) do |info, channel|
|
155
|
+
Thread.pass
|
156
|
+
|
157
|
+
loop do
|
158
|
+
begin
|
159
|
+
sleep info[:interval]
|
160
|
+
@log.debug "retrieving (interval %d) %s..." % [info[:interval], info[:dat].uri]
|
161
|
+
info[:dat].retrieve.last(100).each do |line|
|
162
|
+
priv_line channel, line
|
163
|
+
end
|
164
|
+
|
165
|
+
if info[:dat].length >= 1000
|
166
|
+
post server_name, NOTICE, channel, "Thread is over 1000. Guessing next thread..."
|
167
|
+
guess_next_thread(channel)
|
168
|
+
break
|
169
|
+
end
|
170
|
+
rescue UnknownThread
|
171
|
+
# pass
|
172
|
+
rescue Exception => e
|
173
|
+
@log.error "Error: #{e.inspect}"
|
174
|
+
e.backtrace.each do |l|
|
175
|
+
@log.error "\t#{l}"
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def priv_line(channel, line)
|
183
|
+
post "%d{%s}" % [line.n, line.id], PRIVMSG, channel, line.aa?? encode_aa(line.body) : line.body
|
184
|
+
end
|
185
|
+
|
186
|
+
def encode_aa(aa)
|
187
|
+
uri = URI('http://tinyurl.com/api-create.php')
|
188
|
+
uri.query = 'url=' + URI.escape(<<-EOS.gsub(/[\n\t]/, ''))
|
189
|
+
data:text/html,<pre style='font-family:"IPA モナー Pゴシック"'>#{aa.gsub(/\n/, '<br>')}</pre>
|
190
|
+
EOS
|
191
|
+
Net::HTTP.get(uri.host, uri.request_uri, uri.port)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
if __FILE__ == $0
|
196
|
+
require "optparse"
|
197
|
+
|
198
|
+
opts = {
|
199
|
+
:port => 16701,
|
200
|
+
:host => "localhost",
|
201
|
+
:log => nil,
|
202
|
+
:debug => false,
|
203
|
+
:foreground => false,
|
204
|
+
}
|
205
|
+
|
206
|
+
OptionParser.new do |parser|
|
207
|
+
parser.instance_eval do
|
208
|
+
self.banner = <<-EOB.gsub(/^\t+/, "")
|
209
|
+
Usage: #{$0} [opts]
|
210
|
+
|
211
|
+
EOB
|
212
|
+
|
213
|
+
separator ""
|
214
|
+
|
215
|
+
separator "Options:"
|
216
|
+
on("-p", "--port [PORT=#{opts[:port]}]", "port number to listen") do |port|
|
217
|
+
opts[:port] = port
|
218
|
+
end
|
219
|
+
|
220
|
+
on("-h", "--host [HOST=#{opts[:host]}]", "host name or IP address to listen") do |host|
|
221
|
+
opts[:host] = host
|
222
|
+
end
|
223
|
+
|
224
|
+
on("-l", "--log LOG", "log file") do |log|
|
225
|
+
opts[:log] = log
|
226
|
+
end
|
227
|
+
|
228
|
+
on("--debug", "Enable debug mode") do |debug|
|
229
|
+
opts[:log] = $stdout
|
230
|
+
opts[:debug] = true
|
231
|
+
end
|
232
|
+
|
233
|
+
on("-f", "--foreground", "run foreground") do |foreground|
|
234
|
+
opts[:log] = $stdout
|
235
|
+
opts[:foreground] = true
|
236
|
+
end
|
237
|
+
|
238
|
+
parse!(ARGV)
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
opts[:logger] = Logger.new(opts[:log], "daily")
|
243
|
+
opts[:logger].level = opts[:debug] ? Logger::DEBUG : Logger::INFO
|
244
|
+
|
245
|
+
def daemonize(foreground=false)
|
246
|
+
trap("SIGINT") { exit! 0 }
|
247
|
+
trap("SIGTERM") { exit! 0 }
|
248
|
+
trap("SIGHUP") { exit! 0 }
|
249
|
+
return yield if $DEBUG || foreground
|
250
|
+
Process.fork do
|
251
|
+
Process.setsid
|
252
|
+
Dir.chdir "/"
|
253
|
+
File.open("/dev/null") {|f|
|
254
|
+
STDIN.reopen f
|
255
|
+
STDOUT.reopen f
|
256
|
+
STDERR.reopen f
|
257
|
+
}
|
258
|
+
yield
|
259
|
+
end
|
260
|
+
exit! 0
|
261
|
+
end
|
262
|
+
|
263
|
+
daemonize(opts[:debug] || opts[:foreground]) do
|
264
|
+
Net::IRC::Server.new(opts[:host], opts[:port], NiChannelIrcGateway, opts).start
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|