net-irc 0.0.8 → 0.0.9
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/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
|
+
|