require 'socket' # watches a file, announces new lines on irc # (c) Yoann Guillot 2006 # distributed under the terms of the WtfPLv2 (zoy.org) class IrcClient attr_accessor :host, :port, :nick, :uhost, :chan, :timeout, :msg_interval def initialize(host, port = 6667) @host = host @port = port @uhost= 'rb rb rb :rb' @status = '' # seconds @timeout = 300 # ping if no message during this, reconnect if no pong during this again @allow = Time.now - 10 # next time to watch for a new line (antiflood) @at = [] end def connect @sock = TCPSocket.open @host, @port @sentping = false @lastmsg = Time.now send "user #@uhost" send "nick #@nick" send "join #@chan" @chan = @chan.split(' ').first || @chan end def run connect loop do r, w, e = IO.select [@sock], nil, nil, 0.5 monitor if Time.now > @allow if not r handle_timeout if Time.now - @lastmsg >= @timeout elsif r.include? @sock @lastmsg = Time.now handle_sock @sock.gets.chomp end end end def send(l) if @allow > Time.now @allow = Time.now elsif @allow < Time.now - 10 @allow = Time.now - 10 end @allow += 2 puts "#{Time.now.strftime '%H:%M'} > #{l}" if $VERBOSE @sock.write l + "\r\n" end def handle_timeout if @sentping raise 'server ping timeout' if Time.now - @sentping >= @timeout else send 'ping :stillalive' @sentping = Time.now end end def pm l send "PRIVMSG #@chan :#{l.empty? ? ' ' : l[0, 512]}" end def handle_sock l puts "#{Time.now.strftime '%H:%M'} #{l}" if $VERBOSE and l !~ /^ping/i case l when /^:jj!.* PRIVMSG .* :#@nick:? (.*)/ cmd = $1.strip case cmd when 'status' pm @status when 'quit' send 'quit requested' when /^cat (.*)/ val = $1 begin File.open(val) { |fd| fd.each_line { |l| pm l.chomp } } pm '' if File.size(val) == 0 rescue pm "read #{val}: #$!" end else pm "#{cmd} unknown" end when /^ping (.*)/i send "pong #$1" when /pong.*stillalive/i @sentping = nil end end attr_accessor :file, :filesize def monitor if File.size(@file) != @filesize File.open(@file, 'rb') { |fd| fd.pos = @filesize l = fd.gets if l and not l.empty? # no chomp, send newlines present in the file pm l.chomp case l when /sleep .* => (.*)/ @status = l.chomp end end @filesize = fd.pos } end end end if __FILE__ == $0 if ARGV.empty? c = IrcClient.new 'irc.net' c.chan = '#bla' c.nick = 'logger' c.file = 'watched/file' c.filesize = [0, File.size(c.file) - 400].max # backlog 400 last octets on startup c.run else $stdin.close rescue nil $stdout.close rescue nil $stderr.close rescue nil exit if fork # daemonize loop do exec "ruby #$0" if not pid = fork sleep 300 Process.waitpid(pid) end end end