RubyからGitHubのpull requestをSkypeに通知する(てきとう版)
GitHubのビジネスプランを使ってるんですが、pull requestの通知をチームメンバーが使ってるSkypeチャットに送りたかったので、SkypeでのBotの作り方を調べてみました。
どうにも面倒そうな印象があったんですが、やっぱり結構面倒でしたw
Linux上のマシンでアプリケーションからSkypeにメッセージを送る際には、dbusを経由してコマンドを送る必要があります。
公式のドキュメントは以下。
Skype for Developers
rubyでdbusを使おうと調べてみたら、ruby-dbusというものがあったので、これを使おうとしたんですが、
Skypeを触るのにもっとダイレクトなrypeというライブラリを発見したのでそれを使うことにしました。
詳細はリンク先にあるので省きますが、要はdbusのラッパーですね。
で、こんな感じで書いてみました。
こんなのにaction_viewとか使ってるあたり超手抜き感が溢れてますが・・・。
require "rubygems" require "bundler/setup" require "action_view" require "rype" require "awesome_print" require "simple-rss" require "open-uri" require "yaml" class GithubSkypeNotifier include ActionView::Helpers::SanitizeHelper def initialize(atom_url, chat_id) @atom_url = atom_url @chat_id = chat_id Rype.attach Dir.chdir(File.dirname(__FILE__)) unless File.exist?("notified_list.txt") File.open("notified_list.txt", "w") {|file| puts "Create notified_list.txt"} end notified_list = File.open("notified_list.txt", "r") @notified_items = notified_list.readlines.map{|l| l.chomp}.reduce({}) do |table, item_id| table[item_id] = true table end notified_list.close end def get_items SimpleRSS.parse(open(@atom_url)).items.select {|item| !@notified_items[item.id]} end def notify(item) message = <<EOM ==Github Activity Notify== #{item.title} #{item.link} detail: #{strip_tags(CGI.unescapeHTML(item.content)).gsub(/\s*\n/, "").gsub(/\s+/, " ")} ========================== EOM Rype.chat(@chat_id).send_message(message) puts "send message following:\n#{message}" log_item(item) end def log_item(item) unless @notified_items[item.id] @notified_items[item.id] = true File.open("notified_list.txt", "a") {|file| file.write(item.id + "\n")} end end end def load_config config = YAML.load_file("config.yml") config end config = load_config notifier = GithubSkypeNotifier.new(config["atom_url"], config["chat_id"]) notifier.get_items.each do |item| notifier.notify item end
Gist版 → https://gist.github.com/2850118
面倒だったので、とりあえずActivityのAtom Feed読んで、送ってないitemが来たらSkypeに投げるって感じです。
余計なメッセージも来るけど、とりあえずやりたい事は出来た。
チャットにメッセージを送る時はチャットIDを調べておかなければいけないのですが、
一番調べやすいのは、送りたいチャット窓だけ開いておいて、以下のコードを実行することです。
Rype.attach Rype::Api.invoke("SEARCH ACTIVECHATS") do |a| p a end
チャットIDさえ分かれば、後は結構簡単に送信できます。
ただし、dbusを経由しているため、X関係の環境変数と、DBUS_SESSION_BUS_ADDRESSという環境変数を持っている必要があります。
(詳細は未確認)
X環境下のターミナルから呼ぶなら問題無いんですが、cronとかで動かそうとすると結構ハマります。
とりあえずここのサイトを参考に、シェルスクリプトに環境変数の読み込み処理をかませて、rubyを呼ぶことで対処できました。
でも、再起動したらDBUS_SESSION_BUS_ADDRESS変わりそうなので、安定なボットを作るのはもうちょい工夫が必要ですね。
xvfbを使ってSkypeをヘッドレスで起動するテクニックもあるようですが、まだ試してません。
とりあえずは暫定策なので、これぐらい出来ればいいかなーと。
この辺上手いこといったら、Jenkinsに組込みたいんだけど、そんな暇なさそう。
チームでSkypeを使っていて、外部のイベントをプッシュ通知したい時には使えるかもしれません。
PythonにはSkype4Pyというメジャーなライブラリがあるらしいので、Python使いの人の方が楽そうです・・・。