CUI版mixi station

内定者向けの課題

内定した会社の課題がちょっとおもしろい出題法でよかった。

そのうちのひとつ、おもしろい.bashrcを書けというものがあったので、
ちょっと作ってみた。

CUI版のmixi station

まずは.bashrcから

MIXISTATION=~/mixi_station/mixi.rb
MIXIDIR=~/mixi_station/
if [ -f $MIXISTATION ];then
	echo "mixi station mini";
	alias mtracks="$MIXISTATION tracks";
	alias mnotify="$MIXISTATION notify";
	alias mstop="killall mixi.rb";
	alias mstart="$MIXISTATION start&";
	alias wtracks="less $MIXIDIR/tracks.log";
	alias wnotify="less $MIXIDIR/notify.log";
	$MIXISTATION start&
fi

次にmixi.rbというAtomppを話すクライアント

#!/usr/bin/ruby

require 'net/http'
require 'kconv'
require 'rexml/document'
require 'time'
require 'digest/sha1'
require 'yaml/store'



MIXIID=#mixi id
EMAIL =#Eメールアドレス
PASSWD=#パスワード

class AtomPPClient
	def initialize(server,email,pass)
		@server=server;
		@pass=pass;
		@email=email;
		@header=nil;
	end
	#
	#
	def _wsse_header(email, password)
	  nonce = Array.new(10){ rand(0x100000000) }.pack('I*')
	  nonce_base64 = [nonce].pack("m").chomp # Base64エンコード
	  now = Time.now.utc.iso8601
	  digest = [Digest::SHA1.digest(nonce + now + password)].pack("m").chomp
	  credentials = sprintf(%Q<UsernameToken Username="%s", PasswordDigest="%s", Nonce="%s", Created="%s">,
	                        email, digest, nonce_base64, now)
	  { 'X-WSSE' => credentials }
	end
	def get(rest)
		if @header==nil
			@header=_wsse_header(@email,@pass)
		end
	#	p @header
		Net::HTTP.start(@server,80)do |http|
			response=http.get(rest,@header);
			if(response.body.match(/^<xml/)==nil)
				#response.body.toutf8;
				REXML::Document.new(response.body);
			else
				nil;
			end
		end
	end
end
class MixiChecker
	API={	"tracks"=>"/atom/tracks/r=2/member_id=#{MIXIID}",
			"notify"=>"/atom/notify/r=2/member_id=#{MIXIID}"};
			
	LOG={	"tracks"=>"#{ENV['HOME']}/mixi_station/tracks.log",
			"notify"=>"#{ENV['HOME']}/mixi_station/notify.log"};
			
	LOG_UPDATE="#{ENV['HOME']}/mixi_station/update.yaml";
	
	def initialize()
		@atom=AtomPPClient.new("mixi.jp",EMAIL,PASSWD);
		@db=YAML::Store.new(LOG_UPDATE);
	end
	def check(val)
		last_update={};
		@db.transaction{
			if @db[val]==nil
				last_update[val]=Time.parse("1/1");
			else
				last_update[val]=@db[val];
			end
		}
		data=[]

		@atom.get(API[val]).root.each_element("entry"){|ent|
			if val=="tracks"
				
				update	=Time.parse(ent.elements["updated"].text);
				name	=ent.elements["author/name"].text;
				if update - last_update[val] >0
					data.push({:update=>update,:content=>name.toutf8}) 
				end
			elsif val=="notify"
				update	=Time.parse(ent.elements["updated"].text);
				content	=ent.elements["content"].text;
				if (ent.elements["category"].attributes["term"]!="notice")&&(update - last_update[val] >200)
					data.push({:update=>update,:content=>content}) 
				end
			else
				puts "undefined api";
			end
		}
		data.sort!{|a,b| (a[:update]<=>b[:update])};
		open(LOG[val],"a"){|f|
			if data.length>0
				puts "";
			end
			data.each{|d| 
				f.puts "#{d[:content]}\t#{d[:update]}";
				puts "#{d[:content]}\t#{d[:update]}";
			}
		}

		@db.transaction{
			@db[val]=data.last[:update] if data.length >0
		}
	end
	def start
		["INT","TERM"].each{|sig|trap(sig){puts "shutdown mixi station";exit;}}
		self.check("notify")
		self.check("tracks")
		i=0;
		loop do
		 	if(i%5==0)
		 		#puts "check_notify"
		 		self.check("notify")
		 	else
		 		#puts "check_tracks"
		 		self.check("tracks")
		 	end
		 	sleep(10);
		 	i=i+1;
		end
	end
	
end
case ARGV.shift
	when "start"
		MixiChecker.new.start;
	when "notify"
		puts "mixi station mini check notification...."
		MixiChecker.new.check("notify");
	when "tracks"
		puts "mixi station mini check tracking...."
		MixiChecker.new.check("tracks");
end