net-irc 0.0.2 → 0.0.3
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 +17 -6
- data/Rakefile +0 -5
- data/examples/client.rb +0 -0
- data/examples/lig.rb +102 -28
- data/examples/lingr.rb +29 -36
- data/examples/nig.rb +13 -7
- data/examples/sig.rb +186 -0
- data/examples/tig.rb +210 -76
- data/examples/wig.rb +18 -8
- data/lib/net/irc.rb +23 -21
- data/spec/net-irc_spec.rb +0 -0
- metadata +7 -6
data/examples/nig.rb
CHANGED
@@ -63,7 +63,7 @@ class NowaIrcGateway < TwitterIrcGateway
|
|
63
63
|
end
|
64
64
|
|
65
65
|
def api_base
|
66
|
-
URI("
|
66
|
+
URI("https://api.nowa.jp/")
|
67
67
|
end
|
68
68
|
|
69
69
|
def api_source
|
@@ -83,6 +83,7 @@ if __FILE__ == $0
|
|
83
83
|
:host => "localhost",
|
84
84
|
:log => nil,
|
85
85
|
:debug => false,
|
86
|
+
:foreground => false,
|
86
87
|
}
|
87
88
|
|
88
89
|
OptionParser.new do |parser|
|
@@ -112,6 +113,11 @@ if __FILE__ == $0
|
|
112
113
|
opts[:debug] = true
|
113
114
|
end
|
114
115
|
|
116
|
+
on("-f", "--foreground", "run foreground") do |foreground|
|
117
|
+
opts[:log] = $stdout
|
118
|
+
opts[:foreground] = true
|
119
|
+
end
|
120
|
+
|
115
121
|
parse!(ARGV)
|
116
122
|
end
|
117
123
|
end
|
@@ -119,14 +125,14 @@ if __FILE__ == $0
|
|
119
125
|
opts[:logger] = Logger.new(opts[:log], "daily")
|
120
126
|
opts[:logger].level = opts[:debug] ? Logger::DEBUG : Logger::INFO
|
121
127
|
|
122
|
-
def daemonize(
|
123
|
-
|
128
|
+
def daemonize(foreground=false)
|
129
|
+
trap("SIGINT") { exit! 0 }
|
130
|
+
trap("SIGTERM") { exit! 0 }
|
131
|
+
trap("SIGHUP") { exit! 0 }
|
132
|
+
return yield if $DEBUG || foreground
|
124
133
|
Process.fork do
|
125
134
|
Process.setsid
|
126
135
|
Dir.chdir "/"
|
127
|
-
trap("SIGINT") { exit! 0 }
|
128
|
-
trap("SIGTERM") { exit! 0 }
|
129
|
-
trap("SIGHUP") { exit! 0 }
|
130
136
|
File.open("/dev/null") {|f|
|
131
137
|
STDIN.reopen f
|
132
138
|
STDOUT.reopen f
|
@@ -137,7 +143,7 @@ if __FILE__ == $0
|
|
137
143
|
exit! 0
|
138
144
|
end
|
139
145
|
|
140
|
-
daemonize(opts[:debug]) do
|
146
|
+
daemonize(opts[:debug] || opts[:foreground]) do
|
141
147
|
Net::IRC::Server.new(opts[:host], opts[:port], NowaIrcGateway, opts).start
|
142
148
|
end
|
143
149
|
end
|
data/examples/sig.rb
ADDED
@@ -0,0 +1,186 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
=begin
|
3
|
+
# sig.rb
|
4
|
+
|
5
|
+
ServerLog IRC Gateway
|
6
|
+
|
7
|
+
# Usage
|
8
|
+
|
9
|
+
* Connect.
|
10
|
+
* Join a channel (you can name it as you like)
|
11
|
+
* Set topic "filename regexp"
|
12
|
+
* You will see the log at the channel only matching the regexp.
|
13
|
+
|
14
|
+
=end
|
15
|
+
|
16
|
+
$LOAD_PATH << "lib"
|
17
|
+
$LOAD_PATH << "../lib"
|
18
|
+
|
19
|
+
$KCODE = "u" # json use this
|
20
|
+
|
21
|
+
require "rubygems"
|
22
|
+
require "net/irc"
|
23
|
+
require "logger"
|
24
|
+
require "pathname"
|
25
|
+
require "yaml"
|
26
|
+
|
27
|
+
class ServerLogIrcGateway < Net::IRC::Server::Session
|
28
|
+
def server_name
|
29
|
+
"serverlog"
|
30
|
+
end
|
31
|
+
|
32
|
+
def server_version
|
33
|
+
"0.0.0"
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
def initialize(*args)
|
38
|
+
super
|
39
|
+
@channels = {}
|
40
|
+
@config = Pathname.new(ENV["HOME"]) + ".sig"
|
41
|
+
end
|
42
|
+
|
43
|
+
def on_disconnected
|
44
|
+
@channels.each do |chan, info|
|
45
|
+
begin
|
46
|
+
info[:observer].kill if info[:observer]
|
47
|
+
rescue
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def on_user(m)
|
53
|
+
super
|
54
|
+
@real, *@opts = @real.split(/\s+/)
|
55
|
+
@opts ||= []
|
56
|
+
end
|
57
|
+
|
58
|
+
def on_join(m)
|
59
|
+
channels = m.params.first.split(/,/)
|
60
|
+
channels.each do |channel|
|
61
|
+
@channels[channel] = {
|
62
|
+
:topic => "",
|
63
|
+
:observer => nil,
|
64
|
+
} unless @channels.key?(channel)
|
65
|
+
post @prefix, JOIN, m.params.first
|
66
|
+
post nil, RPL_NAMREPLY, @prefix.nick, "=", channel, "@#{@prefix.nick}"
|
67
|
+
post nil, RPL_ENDOFNAMES, @prefix.nick, channel, "End of NAMES list"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def on_topic(m)
|
72
|
+
channel, topic, = m.params
|
73
|
+
p m.params
|
74
|
+
if @channels.key?(channel)
|
75
|
+
post @prefix, TOPIC, channel, topic
|
76
|
+
@channels[channel][:topic] = topic
|
77
|
+
create_observer(channel)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def create_observer(channel)
|
82
|
+
return unless @channels.key?(channel)
|
83
|
+
info = @channels[channel]
|
84
|
+
@log.debug "create_observer<#{channel}>#{info.inspect}"
|
85
|
+
begin
|
86
|
+
info[:observer].kill if info[:observer]
|
87
|
+
rescue
|
88
|
+
end
|
89
|
+
info[:observer] = Thread.start(channel, info) do |chan, i|
|
90
|
+
file, reg, = i[:topic].split(/\s+/)
|
91
|
+
name = File.basename(file)
|
92
|
+
grep = Regexp.new(reg.to_s)
|
93
|
+
@log.info "#{file} / grep => #{grep.inspect}"
|
94
|
+
File.open(file) do |f|
|
95
|
+
size = File.size(f)
|
96
|
+
f.seek size
|
97
|
+
loop do
|
98
|
+
sleep 1
|
99
|
+
nsize = File.size(f)
|
100
|
+
if nsize > size
|
101
|
+
@log.debug "follow up log"
|
102
|
+
l = f.gets
|
103
|
+
if grep === l
|
104
|
+
post name, PRIVMSG, chan, l
|
105
|
+
end
|
106
|
+
end
|
107
|
+
size = nsize
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
if __FILE__ == $0
|
115
|
+
require "optparse"
|
116
|
+
|
117
|
+
opts = {
|
118
|
+
:port => 16700,
|
119
|
+
:host => "localhost",
|
120
|
+
:log => nil,
|
121
|
+
:debug => false,
|
122
|
+
:foreground => false,
|
123
|
+
}
|
124
|
+
|
125
|
+
OptionParser.new do |parser|
|
126
|
+
parser.instance_eval do
|
127
|
+
self.banner = <<-EOB.gsub(/^\t+/, "")
|
128
|
+
Usage: #{$0} [opts]
|
129
|
+
|
130
|
+
EOB
|
131
|
+
|
132
|
+
separator ""
|
133
|
+
|
134
|
+
separator "Options:"
|
135
|
+
on("-p", "--port [PORT=#{opts[:port]}]", "port number to listen") do |port|
|
136
|
+
opts[:port] = port
|
137
|
+
end
|
138
|
+
|
139
|
+
on("-h", "--host [HOST=#{opts[:host]}]", "host name or IP address to listen") do |host|
|
140
|
+
opts[:host] = host
|
141
|
+
end
|
142
|
+
|
143
|
+
on("-l", "--log LOG", "log file") do |log|
|
144
|
+
opts[:log] = log
|
145
|
+
end
|
146
|
+
|
147
|
+
on("--debug", "Enable debug mode") do |debug|
|
148
|
+
opts[:log] = $stdout
|
149
|
+
opts[:debug] = true
|
150
|
+
end
|
151
|
+
|
152
|
+
on("-f", "--foreground", "run foreground") do |foreground|
|
153
|
+
opts[:log] = $stdout
|
154
|
+
opts[:foreground] = true
|
155
|
+
end
|
156
|
+
|
157
|
+
parse!(ARGV)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
opts[:logger] = Logger.new(opts[:log], "daily")
|
162
|
+
opts[:logger].level = opts[:debug] ? Logger::DEBUG : Logger::INFO
|
163
|
+
|
164
|
+
def daemonize(foreground=false)
|
165
|
+
trap("SIGINT") { exit! 0 }
|
166
|
+
trap("SIGTERM") { exit! 0 }
|
167
|
+
trap("SIGHUP") { exit! 0 }
|
168
|
+
return yield if $DEBUG || foreground
|
169
|
+
Process.fork do
|
170
|
+
Process.setsid
|
171
|
+
Dir.chdir "/"
|
172
|
+
File.open("/dev/null") {|f|
|
173
|
+
STDIN.reopen f
|
174
|
+
STDOUT.reopen f
|
175
|
+
STDERR.reopen f
|
176
|
+
}
|
177
|
+
yield
|
178
|
+
end
|
179
|
+
exit! 0
|
180
|
+
end
|
181
|
+
|
182
|
+
daemonize(opts[:debug] || opts[:foreground]) do
|
183
|
+
Net::IRC::Server.new(opts[:host], opts[:port], ServerLogIrcGateway, opts).start
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
data/examples/tig.rb
CHANGED
@@ -23,7 +23,7 @@ Configuration example for Tiarra ( http://coderepos.org/share/wiki/Tiarra ).
|
|
23
23
|
twitter {
|
24
24
|
host: localhost
|
25
25
|
port: 16668
|
26
|
-
name: username@example.com athack
|
26
|
+
name: username@example.com athack jabber=username@example.com:jabberpasswd
|
27
27
|
password: password on Twitter
|
28
28
|
in-encoding: utf8
|
29
29
|
out-encoding: utf8
|
@@ -65,8 +65,9 @@ $LOAD_PATH << "../lib"
|
|
65
65
|
$KCODE = "u" # json use this
|
66
66
|
|
67
67
|
require "rubygems"
|
68
|
-
require "net/http"
|
69
68
|
require "net/irc"
|
69
|
+
require "net/http"
|
70
|
+
require "net/https"
|
70
71
|
require "uri"
|
71
72
|
require "json"
|
72
73
|
require "socket"
|
@@ -74,7 +75,6 @@ require "time"
|
|
74
75
|
require "logger"
|
75
76
|
require "yaml"
|
76
77
|
require "pathname"
|
77
|
-
require "digest/md5"
|
78
78
|
require "cgi"
|
79
79
|
|
80
80
|
Net::HTTP.version_1_2
|
@@ -108,10 +108,11 @@ class TwitterIrcGateway < Net::IRC::Server::Session
|
|
108
108
|
|
109
109
|
def initialize(*args)
|
110
110
|
super
|
111
|
-
@groups
|
112
|
-
@channels
|
111
|
+
@groups = {}
|
112
|
+
@channels = [] # joined channels (groups)
|
113
113
|
@user_agent = "#{self.class}/#{server_version} (tig.rb)"
|
114
|
-
@config
|
114
|
+
@config = Pathname.new(ENV["HOME"]) + ".tig"
|
115
|
+
@map = nil
|
115
116
|
load_config
|
116
117
|
end
|
117
118
|
|
@@ -120,8 +121,9 @@ class TwitterIrcGateway < Net::IRC::Server::Session
|
|
120
121
|
post @prefix, JOIN, main_channel
|
121
122
|
post server_name, MODE, main_channel, "+o", @prefix.nick
|
122
123
|
|
123
|
-
@real, *@opts = @real.split(/\s+/)
|
124
|
+
@real, *@opts = @opts.name || @real.split(/\s+/)
|
124
125
|
@opts ||= []
|
126
|
+
@tmap = TypableMap.new
|
125
127
|
|
126
128
|
jabber = @opts.find {|i| i =~ /^jabber=(\S+?):(\S+)/ }
|
127
129
|
if jabber
|
@@ -145,7 +147,7 @@ class TwitterIrcGateway < Net::IRC::Server::Session
|
|
145
147
|
@log.info "Client Options: #{@opts.inspect}"
|
146
148
|
|
147
149
|
@timeline = []
|
148
|
-
Thread.start do
|
150
|
+
@check_friends_thread = Thread.start do
|
149
151
|
loop do
|
150
152
|
begin
|
151
153
|
check_friends
|
@@ -157,14 +159,14 @@ class TwitterIrcGateway < Net::IRC::Server::Session
|
|
157
159
|
@log.error "\t#{l}"
|
158
160
|
end
|
159
161
|
end
|
160
|
-
sleep 10 * 60
|
162
|
+
sleep 10 * 60 # 6 times/hour
|
161
163
|
end
|
162
164
|
end
|
163
165
|
sleep 3
|
164
166
|
|
165
167
|
return if jabber
|
166
168
|
|
167
|
-
Thread.start do
|
169
|
+
@check_timeline_thread = Thread.start do
|
168
170
|
loop do
|
169
171
|
begin
|
170
172
|
check_timeline
|
@@ -177,18 +179,31 @@ class TwitterIrcGateway < Net::IRC::Server::Session
|
|
177
179
|
@log.error "\t#{l}"
|
178
180
|
end
|
179
181
|
end
|
180
|
-
sleep
|
182
|
+
sleep 180 # 20 times/hour
|
181
183
|
end
|
182
184
|
end
|
183
185
|
end
|
184
186
|
|
187
|
+
def on_disconnected
|
188
|
+
@check_friends_thread.kill rescue nil
|
189
|
+
@check_timeline_thread.kill rescue nil
|
190
|
+
@im_thread.kill rescue nil
|
191
|
+
@im.disconnect rescue nil
|
192
|
+
end
|
193
|
+
|
185
194
|
def on_privmsg(m)
|
195
|
+
return on_ctcp(m[0], ctcp_decoding(m[1])) if m.ctcp?
|
186
196
|
retry_count = 3
|
187
197
|
ret = nil
|
188
198
|
target, message = *m.params
|
189
199
|
begin
|
190
200
|
if target =~ /^#/
|
191
|
-
|
201
|
+
if @im && @im.connected? # in jabber mode, using jabber post
|
202
|
+
ret = @im.deliver(jabber_bot_id, message)
|
203
|
+
post "#{nick}!#{nick}@#{api_base.host}", TOPIC, main_channel, untinyurl(message)
|
204
|
+
else
|
205
|
+
ret = api("statuses/update", {"status" => message})
|
206
|
+
end
|
192
207
|
else
|
193
208
|
# direct message
|
194
209
|
ret = api("direct_messages/new", {"user" => target, "text" => message})
|
@@ -207,6 +222,34 @@ class TwitterIrcGateway < Net::IRC::Server::Session
|
|
207
222
|
end
|
208
223
|
end
|
209
224
|
|
225
|
+
def on_ctcp(target, message)
|
226
|
+
_, command, *args = message.split(/\s+/)
|
227
|
+
case command
|
228
|
+
when "list"
|
229
|
+
nick = args[0]
|
230
|
+
@log.debug([ nick, message ])
|
231
|
+
res = api('statuses/user_timeline', { 'id' => nick }).reverse_each do |s|
|
232
|
+
@log.debug(s)
|
233
|
+
post nick, NOTICE, main_channel, "#{generate_status_message(s)}"
|
234
|
+
end
|
235
|
+
|
236
|
+
unless res
|
237
|
+
post nil, ERR_NOSUCHNICK, nick, "No such nick/channel"
|
238
|
+
end
|
239
|
+
when "fav"
|
240
|
+
tid = args[0]
|
241
|
+
id = @tmap[tid]
|
242
|
+
if id
|
243
|
+
res = api("favorites/create/#{id}", {})
|
244
|
+
post nil, NOTICE, main_channel, "Fav: #{res["screen_name"]}: #{res["text"]}"
|
245
|
+
else
|
246
|
+
post nil, NOTICE, main_channel, "No such id #{tid}"
|
247
|
+
end
|
248
|
+
end
|
249
|
+
rescue ApiFailed => e
|
250
|
+
log e.inspect
|
251
|
+
end
|
252
|
+
|
210
253
|
def on_whois(m)
|
211
254
|
nick = m.params[0]
|
212
255
|
f = (@friends || []).find {|i| i["screen_name"] == nick }
|
@@ -298,32 +341,25 @@ class TwitterIrcGateway < Net::IRC::Server::Session
|
|
298
341
|
|
299
342
|
private
|
300
343
|
def check_timeline
|
301
|
-
|
302
|
-
@prev_time
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
#
|
307
|
-
|
308
|
-
|
344
|
+
@prev_time ||= Time.at(0)
|
345
|
+
api("statuses/friends_timeline", {"since" => @prev_time.httpdate}).reverse_each do |s|
|
346
|
+
id = s["id"] || s["rid"]
|
347
|
+
next if id.nil? || @timeline.include?(id)
|
348
|
+
@timeline << id
|
349
|
+
nick = s["user_login_id"] || s["user"]["screen_name"] # it may be better to use user_login_id in Wassr
|
350
|
+
mesg = generate_status_message(s)
|
351
|
+
|
352
|
+
tid = @tmap.push(id)
|
353
|
+
|
354
|
+
@log.debug [id, nick, mesg]
|
355
|
+
if nick == @nick # 自分のときは topic に
|
356
|
+
post "#{nick}!#{nick}@#{api_base.host}", TOPIC, main_channel, untinyurl(mesg)
|
357
|
+
else
|
358
|
+
message(nick, main_channel, "%s [%s]" % [mesg, tid])
|
309
359
|
end
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
digest = Digest::MD5.hexdigest("#{nick}::#{mesg}")
|
315
|
-
unless @timeline.include?(digest)
|
316
|
-
@timeline << digest
|
317
|
-
@log.debug [nick, mesg]
|
318
|
-
if nick == @nick # 自分のときは topic に
|
319
|
-
post nick, TOPIC, main_channel, mesg
|
320
|
-
else
|
321
|
-
message(nick, main_channel, mesg)
|
322
|
-
end
|
323
|
-
@groups.each do |channel,members|
|
324
|
-
if members.include?(nick)
|
325
|
-
message(nick, channel, mesg)
|
326
|
-
end
|
360
|
+
@groups.each do |channel, members|
|
361
|
+
if members.include?(nick)
|
362
|
+
message(nick, channel, "%s [%s]" % [mesg, tid])
|
327
363
|
end
|
328
364
|
end
|
329
365
|
end
|
@@ -332,10 +368,34 @@ class TwitterIrcGateway < Net::IRC::Server::Session
|
|
332
368
|
@prev_time = Time.now
|
333
369
|
end
|
334
370
|
|
371
|
+
def generate_status_message(status)
|
372
|
+
s = status
|
373
|
+
mesg = s["text"]
|
374
|
+
@log.debug(mesg)
|
375
|
+
|
376
|
+
# added @user in no use @user reply message ( Wassr only )
|
377
|
+
if s.has_key?('reply_status_url') and s['reply_status_url'] and s['text'] !~ /^@.*/ and %r{([^/]+)/statuses/[^/]+}.match(s['reply_status_url'])
|
378
|
+
reply_user_id = $1
|
379
|
+
mesg = "@#{reply_user_id} #{mesg}"
|
380
|
+
end
|
381
|
+
# display area name(Wassr only)
|
382
|
+
if s.has_key?('areaname') and s["areaname"]
|
383
|
+
mesg += " L: #{s['areaname']}"
|
384
|
+
end
|
385
|
+
# display photo url(Wassr only)
|
386
|
+
if s.has_key?('photo_url') and s["photo_url"]
|
387
|
+
mesg += " #{s['photo_url']}"
|
388
|
+
end
|
389
|
+
|
390
|
+
# time = Time.parse(s["created_at"]) rescue Time.now
|
391
|
+
m = { """ => "\"", "<"=> "<", ">"=> ">", "&"=> "&", "\n" => " "}
|
392
|
+
mesg.gsub!(/(#{m.keys.join("|")})/) { m[$1] }
|
393
|
+
mesg
|
394
|
+
end
|
395
|
+
|
335
396
|
def check_direct_messages
|
336
|
-
|
337
|
-
@prev_time_d
|
338
|
-
api("direct_messages", {"since" => [@prev_time_d.httpdate] }).reverse_each do |s|
|
397
|
+
@prev_time_d ||= Time.now
|
398
|
+
api("direct_messages", {"since" => @prev_time_d.httpdate}).reverse_each do |s|
|
339
399
|
nick = s["sender_screen_name"]
|
340
400
|
mesg = s["text"]
|
341
401
|
time = Time.parse(s["created_at"])
|
@@ -356,6 +416,10 @@ class TwitterIrcGateway < Net::IRC::Server::Session
|
|
356
416
|
else
|
357
417
|
prv_friends = @friends.map {|i| i["screen_name"] }
|
358
418
|
now_friends = friends.map {|i| i["screen_name"] }
|
419
|
+
|
420
|
+
# twitter api bug?
|
421
|
+
return if !first && (now_friends.length - prv_friends.length).abs > 10
|
422
|
+
|
359
423
|
(now_friends - prv_friends).each do |join|
|
360
424
|
join = "@#{join}" if @opts.include?("athack")
|
361
425
|
post "#{join}!#{join}@#{api_base.host}", JOIN, main_channel
|
@@ -370,16 +434,16 @@ class TwitterIrcGateway < Net::IRC::Server::Session
|
|
370
434
|
|
371
435
|
def start_jabber(jid, pass)
|
372
436
|
@log.info "Logging-in with #{jid} -> jabber_bot_id: #{jabber_bot_id}"
|
373
|
-
im = Jabber::Simple.new(jid, pass)
|
374
|
-
im.add(jabber_bot_id)
|
375
|
-
Thread.start do
|
437
|
+
@im = Jabber::Simple.new(jid, pass)
|
438
|
+
@im.add(jabber_bot_id)
|
439
|
+
@im_thread = Thread.start do
|
376
440
|
loop do
|
377
441
|
begin
|
378
|
-
im.received_messages.each do |msg|
|
442
|
+
@im.received_messages.each do |msg|
|
379
443
|
@log.debug [msg.from, msg.body]
|
380
444
|
if msg.from.strip == jabber_bot_id
|
381
|
-
#
|
382
|
-
#
|
445
|
+
# Twitter -> 'id: msg'
|
446
|
+
# Wassr -> 'nick(id): msg'
|
383
447
|
body = msg.body.sub(/^(.+?)(?:\((.+?)\))?: /, "")
|
384
448
|
if Regexp.last_match
|
385
449
|
nick, id = Regexp.last_match.captures
|
@@ -402,7 +466,7 @@ class TwitterIrcGateway < Net::IRC::Server::Session
|
|
402
466
|
def save_config
|
403
467
|
config = {
|
404
468
|
:channels => @channels,
|
405
|
-
:groups
|
469
|
+
:groups => @groups,
|
406
470
|
}
|
407
471
|
@config.open("w") do |f|
|
408
472
|
YAML.dump(config, f)
|
@@ -419,45 +483,61 @@ class TwitterIrcGateway < Net::IRC::Server::Session
|
|
419
483
|
end
|
420
484
|
|
421
485
|
def api(path, q={})
|
422
|
-
ret
|
423
|
-
|
424
|
-
|
486
|
+
ret = {}
|
487
|
+
header = {
|
488
|
+
"User-Agent" => @user_agent,
|
489
|
+
"Authorization" => "Basic " + ["#{@real}:#{@pass}"].pack("m"),
|
490
|
+
"X-Twitter-Client" => api_source,
|
491
|
+
"X-Twitter-Client-Version" => server_version,
|
492
|
+
"X-Twitter-Client-URL" => "http://coderepos.org/share/browser/lang/ruby/misc/tig.rb",
|
493
|
+
}
|
494
|
+
header["If-Modified-Since"] = q["since"] if q.key?("since")
|
495
|
+
|
496
|
+
q["source"] ||= api_source
|
425
497
|
q = q.inject([]) {|r,(k,v)| v.inject(r) {|r,i| r << "#{k}=#{URI.escape(i, /[^-.!~*'()\w]/n)}" } }.join("&")
|
498
|
+
|
426
499
|
uri = api_base.dup
|
427
|
-
uri.path = path
|
500
|
+
uri.path = path.sub(%r{^/*}, "/") << ".json"
|
428
501
|
uri.query = q
|
502
|
+
|
429
503
|
@log.debug uri.inspect
|
430
|
-
Net::HTTP.
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
504
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
505
|
+
if uri.scheme == "https"
|
506
|
+
http.use_ssl = true
|
507
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE # FIXME
|
508
|
+
end
|
509
|
+
http.start do
|
510
|
+
case uri.path
|
436
511
|
when "/statuses/update.json", "/direct_messages/new.json"
|
437
512
|
ret = http.post(uri.request_uri, q, header)
|
438
513
|
else
|
439
514
|
ret = http.get(uri.request_uri, header)
|
440
515
|
end
|
441
516
|
end
|
442
|
-
|
443
|
-
case ret
|
444
|
-
when
|
445
|
-
JSON.parse(ret.body.gsub(/'(y(?:es)?|
|
446
|
-
|
517
|
+
|
518
|
+
case ret
|
519
|
+
when Net::HTTPOK # 200
|
520
|
+
ret = JSON.parse(ret.body.gsub(/'(y(?:es)?|no?|true|false|null)'/, '"\1"'))
|
521
|
+
raise ApiFailed, "Server Returned Error: #{ret["error"]}" if ret.kind_of?(Hash) && ret["error"]
|
522
|
+
ret
|
523
|
+
when Net::HTTPNotModified # 304
|
447
524
|
[]
|
525
|
+
when Net::HTTPBadRequest # 400
|
526
|
+
# exceeded the rate limitation
|
527
|
+
raise ApiFailed, "#{ret.code}: #{ret["error"]}"
|
448
528
|
else
|
449
|
-
raise ApiFailed, "Server Returned #{ret.code}"
|
529
|
+
raise ApiFailed, "Server Returned #{ret.code} #{ret.message}"
|
450
530
|
end
|
451
531
|
rescue Errno::ETIMEDOUT, JSON::ParserError, IOError, Timeout::Error, Errno::ECONNRESET => e
|
452
532
|
raise ApiFailed, e.inspect
|
453
533
|
end
|
454
534
|
|
455
535
|
def message(sender, target, str)
|
456
|
-
#
|
457
|
-
#
|
458
|
-
#
|
459
|
-
str
|
460
|
-
sender =
|
536
|
+
# str.gsub!(/&#(x)?([0-9a-f]+);/i) do
|
537
|
+
# [$1 ? $2.hex : $2.to_i].pack("U")
|
538
|
+
# end
|
539
|
+
str = untinyurl(str)
|
540
|
+
sender = "#{sender}!#{sender}@#{api_base.host}"
|
461
541
|
post sender, PRIVMSG, target, str
|
462
542
|
end
|
463
543
|
|
@@ -469,17 +549,58 @@ class TwitterIrcGateway < Net::IRC::Server::Session
|
|
469
549
|
def untinyurl(text)
|
470
550
|
text.gsub(%r|http://(preview\.)?tinyurl\.com/[0-9a-z=]+|i) {|m|
|
471
551
|
uri = URI(m)
|
472
|
-
uri.host = uri.host.sub($1,
|
552
|
+
uri.host = uri.host.sub($1, "") if $1
|
473
553
|
Net::HTTP.start(uri.host, uri.port) {|http|
|
474
554
|
http.open_timeout = 3
|
475
555
|
begin
|
476
|
-
http.head(uri.request_uri, {
|
556
|
+
http.head(uri.request_uri, { "User-Agent" => @user_agent })["Location"] || m
|
477
557
|
rescue Timeout::Error
|
478
558
|
m
|
479
559
|
end
|
480
560
|
}
|
481
561
|
}
|
482
562
|
end
|
563
|
+
|
564
|
+
class TypableMap < Hash
|
565
|
+
Roma = "a i u e o k g s z t d n h b p m y r w j v l q".split(/ /).map {|k|
|
566
|
+
%w|a i u e o|.map {|v| "#{k}#{v}" }
|
567
|
+
}.flatten
|
568
|
+
|
569
|
+
def initialize(size=2)
|
570
|
+
@seq = Roma
|
571
|
+
@map = {}
|
572
|
+
@n = 0
|
573
|
+
@size = size
|
574
|
+
end
|
575
|
+
|
576
|
+
def generate(n)
|
577
|
+
ret = []
|
578
|
+
begin
|
579
|
+
n, r = n.divmod(@seq.size)
|
580
|
+
ret << @seq[r]
|
581
|
+
end while n > 0
|
582
|
+
ret.reverse.join
|
583
|
+
end
|
584
|
+
|
585
|
+
def push(obj)
|
586
|
+
id = generate(@n)
|
587
|
+
self[id] = obj
|
588
|
+
@n += 1
|
589
|
+
@n = @n % (@seq.size ** @size)
|
590
|
+
id
|
591
|
+
end
|
592
|
+
alias << push
|
593
|
+
|
594
|
+
def clear
|
595
|
+
@n = 0
|
596
|
+
super
|
597
|
+
end
|
598
|
+
|
599
|
+
private :[]=
|
600
|
+
undef update, merge, merge!, replace
|
601
|
+
end
|
602
|
+
|
603
|
+
|
483
604
|
end
|
484
605
|
|
485
606
|
if __FILE__ == $0
|
@@ -490,6 +611,7 @@ if __FILE__ == $0
|
|
490
611
|
:host => "localhost",
|
491
612
|
:log => nil,
|
492
613
|
:debug => false,
|
614
|
+
:foreground => false,
|
493
615
|
}
|
494
616
|
|
495
617
|
OptionParser.new do |parser|
|
@@ -519,6 +641,15 @@ if __FILE__ == $0
|
|
519
641
|
opts[:debug] = true
|
520
642
|
end
|
521
643
|
|
644
|
+
on("-f", "--foreground", "run foreground") do |foreground|
|
645
|
+
opts[:log] = $stdout
|
646
|
+
opts[:foreground] = true
|
647
|
+
end
|
648
|
+
|
649
|
+
on("-n", "--name [user name or email address]") do |name|
|
650
|
+
opts[:name] = name
|
651
|
+
end
|
652
|
+
|
522
653
|
parse!(ARGV)
|
523
654
|
end
|
524
655
|
end
|
@@ -526,14 +657,14 @@ if __FILE__ == $0
|
|
526
657
|
opts[:logger] = Logger.new(opts[:log], "daily")
|
527
658
|
opts[:logger].level = opts[:debug] ? Logger::DEBUG : Logger::INFO
|
528
659
|
|
529
|
-
def daemonize(
|
530
|
-
|
660
|
+
def daemonize(foreground=false)
|
661
|
+
trap("SIGINT") { exit! 0 }
|
662
|
+
trap("SIGTERM") { exit! 0 }
|
663
|
+
trap("SIGHUP") { exit! 0 }
|
664
|
+
return yield if $DEBUG || foreground
|
531
665
|
Process.fork do
|
532
666
|
Process.setsid
|
533
667
|
Dir.chdir "/"
|
534
|
-
trap("SIGINT") { exit! 0 }
|
535
|
-
trap("SIGTERM") { exit! 0 }
|
536
|
-
trap("SIGHUP") { exit! 0 }
|
537
668
|
File.open("/dev/null") {|f|
|
538
669
|
STDIN.reopen f
|
539
670
|
STDOUT.reopen f
|
@@ -544,8 +675,11 @@ if __FILE__ == $0
|
|
544
675
|
exit! 0
|
545
676
|
end
|
546
677
|
|
547
|
-
daemonize(opts[:debug]) do
|
678
|
+
daemonize(opts[:debug] || opts[:foreground]) do
|
548
679
|
Net::IRC::Server.new(opts[:host], opts[:port], TwitterIrcGateway, opts).start
|
549
680
|
end
|
550
681
|
end
|
551
682
|
|
683
|
+
# Local Variables:
|
684
|
+
# coding: utf-8
|
685
|
+
# End:
|