Skip to content

Instantly share code, notes, and snippets.

@shyouhei
Created December 13, 2011 11:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save shyouhei/1471818 to your computer and use it in GitHub Desktop.
Save shyouhei/1471818 to your computer and use it in GitHub Desktop.
#! /bin/ruby1.8.7 -Ku
require 'socket'
require 'open-uri'
require 'time'
require 'json'
require 'base64'
def cut str, len=100
a = str.scan /./u
b = if a.size >= len - 3
a[0, 99] + %w[ . . . ]
else
a
end
b.join
end
def notice fp, ch, msg
msg.chomp!
msg << "\n"
fp.write NKF.nkf('-cWjm0', msg).gsub(/^/, "NOTICE #{ch} :")
STDERR.puts "#{ch} #{msg}"
sleep 0.3
#fp.write msg
#fp.puts
#fp.flush
end
$last = Time.at 0
$etag = Hash.new ''.freeze
def evaluate fq, &block
j = JSON.load fq
j.reject! do |i|
case i["type"]
when "WatchEvent", "PushEvent", "ForkEvent"
true
else
false
end
end
if j.empty?
case fq.meta["link"] when /<(.*?)>; rel="next"/ then
uri = URI.parse $1
follow uri.freeze, &block
end
else
j.map! do |i| i["created_at"] = Time.iso8601 i["created_at"]; i end
j.reject! do |i| i["created_at"] <= $last end
if j.empty?
# STDERR.puts "no more."
else
a = j.sort_by do |i| i["created_at"] end
a.each do |i|
$last = [i["created_at"], $last].max
case i["type"]
when "PullRequestEvent"
user = i["actor"]["login"]
action = i["payload"]["action"]
number = i["payload"]["number"]
link = i["payload"]["pull_request"]["html_url"]
title = i["payload"]["pull_request"]["title"]
yield %'@#{user} #{action} pull request ##{number} "#{cut title}" #{link}'
when "IssueCommentEvent"
user = i["actor"]["login"]
action = case i["payload"]["action"] when "created" then "posted" else i["payload"]["action"] end
link = i["payload"]["issue"]["html_url"]
title = i["payload"]["comment"]["body"]
yield %'@#{user} #{action} comment "#{cut title}" #{link}'
when "CommitCommentEvent"
user = i["actor"]["login"]
link = i["payload"]["comment"]["html_url"]
title = i["payload"]["comment"]["body"]
yield %'@#{user} commented "#{cut title}" #{link}'
else
yield i.inspect
end
end
# puts "#{a.size}"
end
end
end
def follow uri, &block
opt = {
"If-Modified-Since" => $last.httpdate,
"If-None-Match" => $etag[uri],
"User-Agent" => RUBY_DESCRIPTION,
"Authorization" => "Basic deadbeef=="
}
begin
uri.open opt do |fq|
case fq.status[0]
when /^200/
evaluate fq, &block
else
p fq.status, fq.meta
end
$etag[uri] = fq.meta["etag"]
end
rescue OpenURI::HTTPError => e
# ok
end
end
def poller_thread &block
uri = URI.parse "https://api.github.com/repos/ruby/ruby/events".freeze
loop do
Thread.stop # waken up by other thread
follow uri.freeze, &block
end
end
def timer_thread &block
th = Thread.start { poller_thread(&block) }
th.abort_on_exception = true
loop do
th.wakeup
sleep 20
end
end
STDIN.close
# lambda hack to ensure GC... top-level scope is a GC root so any local
# variables written on top of file will never be sweeped.
lambda do |user, pass, host, port, channel|
rexp = %r'\A:(.+?)(?:!.+?)? PRIVMSG (.+?) :?(.*)\z'uo
invt = %r'\A(?:\S+?)? INVITE (\S+) (.*)\z'uo
ping = %r'\APING (.*)\z'uo
repl = %r'\A:\S+ 43\d \* \S+? :Nick'uo
begin
TCPSocket.open host, port || '6667' do |fp|
fp.sync = true
nick = 'gugurecus'
fp.printf "PASS %s\r\n", pass if pass
proc = lambda do
fp.write "QUIT :got signal, restarting...\r\n"
fp.shutdown
raise "signaled. normal shutdown."
end
Signal.trap(%s'INT', &proc)
Signal.trap(%s'TERM', &proc)
Signal.trap(%s'KILL', &proc)
l = fp.gets
fp.printf "USER %s localhost %s :IRC-shell gateway\r\n",
user || 'shyouhei', host
fp.printf "NICK %s\r\n", nick
fp.printf "JOIN %s\r\n", channel unless channel.empty?
STDERR.puts "start loop"
timer_thread do |msg|
notice fp, channel, msg
end
while l = fp.gets do
l = NKF.nkf('-Jwm0', l)
if m = ping.match(l.chomp) then
fp.printf "PONG %s\r\n", m[1]
# elsif m = invt.match(l.chomp) then
# fp.printf "JOIN %s\r\n", m[2]
# elsif m = rexp.match(l.chomp) then
# evaluate fp, *m.captures
end
end
end
rescue Errno::ECONNRESET => e
retry
rescue => e
require 'pp'
p e.message
pp e.backtrace
Signal.trap(%s'INT', 'DEFAULT') # reset
Signal.trap(%s'TERM', 'DEFAULT') # reset
Signal.trap(%s'KILL', 'DEFAULT') # reset
# retry
end
end.call(*lambda do |argv|
usage = %q"usage: #$0 irc://[user:pass@]host:port/#channel"
rexp = %r'\A(?:irc://)?(?:(.*?):(.*?)@)?(.*?)(?::(.*?))?/(.*)\z'o
abort usage if argv.size != 1
abort usage unless m = rexp.match(argv.shift)
m.captures
end.call(ARGV))
#
# Local Variables:
# mode: ruby
# coding: utf-8
# indent-tabs-mode: t
# tab-width: 3
# ruby-indent-level: 3
# fill-column: 79
# default-justification: full
# End:
# vi: ts=3 sw=3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment