BotkitでSlack Botを作りつつ自己アップデートできるようにした
Slack皆さん使ってますか?
Slackはただチャットが出来るだけではなく豊富なAPIによってもたらされる便利Botたちの存在が非常に大きいです.
Botを開発する際には,Githubが開発しているHubotが有名ですが,ここ最近ではSlack botに特化した(別に特化しているわけでもなさそう)BotkitというBotフレームワークが出ました.
Botの設置自体はリポジトリのREADME.mdを見ればわかるので,見てください. で,自己アップデートというのは何かって言うと,Botのコードを書き換えてpushした後に設置しているサーバにログインして,pullしてrestartするっていう作業がめっちゃだるかったので,自分で自分を更新して再起動させる仕組みを作りました.
基本的なコンセプトは HubotでHubotの更新をforeverを利用してHubotにさせてみる - MANA-DOT ここから得ました.ありがとうございます.
foreverでの起動
まず,参考ページの通りforeverでの起動をします. 元リポジトリの起動方法だと,tokenを環境変数で与えるようになっていますが,foreverでの環境変数の与え方がわからなかったので,Botのソース内に直書きするかファイルを読む仕組みにしましょう.
forever start bot.js
これで起動はできます.
参考ページにもある通り,foreverは死んでもうまいこと生き返らせてくれる機能を持っているので,アップデート処理が終わったら自殺するというコードをかけば良いでしょう.
アップデート処理
まずはコードを出します.
var child_process = require('child_process'); function updateSelf(bot, message){ child_process.exec('git reset --hard origin/master', function(error, stdout, stderr){ bot.reply(message, 'Botが更新されました!'); bot.reply(message, 'Botを再起動します'); setTimeout(function(){ process.exit(); }, 2000); }); } controller.hears(['update'], 'direct_mention', function(bot, message) { bot.reply(message, 'Botのアップデートを開始します'); child_process.exec('git fetch', function(error, stdout, stderr){ child_process.exec('git log master..origin/master', function(error, stdout, stderr){ if(stdout == ""){ bot.reply(message, 'Botは最新です'); }else{ bot.startConversation(message, function(error, convo){ bot.reply(message, '更新内容は以下のとおりです'); bot.reply(message, '```\n' + stdout + '\n```'); convo.ask('アップデートを行いますか?(y/n)', [ { pattern: bot.utterances.yes, callback: function(response, convo){ updateSelf(bot, message); convo.next(); } }, { pattern: bot.utterances.no, callback: function(response, convo){ bot.reply(message, 'アップデートを中止します'); convo.next(); } }, { pattern: 'じゃあそれで', callback: function(response, convo){ updateSelf(bot, message); convo.next(); } }, { default: true, callback: function(response, convo){ convo.repeat(); convo.next(); } } ]); }); } }); }); });
まずgitを操作したりするために,コマンド実行可能な child_process
を利用します.
update
コマンドが発行された時にまず,git fetchを行い,アップデートの確認を行います.
アップデートがあるのであれば,なんらかの標準出力がなされるので,それでアップデートがあるかどうかを判定します.
アップデートがある場合は,変更点を git log
で出力するようにしました.
また,BotkitのConversation機能を用いて,アップデートを行うかどうかの確認を行う仕組みを導入しました.
アップデートが許可された場合には, git reset --hard origin/master
とすることで,origin/master
への追従を行い,最新版へのコード更新が行われます.
その後, process.exit()
を発行し,自殺した後foreverによって再び生かされることになります.
process.exit()
を発行するときの setTimeout
が無いと,bot.reply()
が間に合わず何も出力されないケースがあるので,適当に時間とって setTimeout
した方がいいです.
実行時の様子
終わり
これでBot開発が捗る.
記事を自分で読み返して, git fetch
しておいて,アップデートを了承しなかった場合,もう一度updateした時には,fetchが働かず永久にupdateできないというバグを見つけてしまった. アップデートがあるかどうかの判定を git log master..origin/master
でやれば良さそう.
NearbyでAndroid,iOS通信(解説は元気が出たら)
久々にこっちで書く.
NearbyというのはGoogleが提供しているpub-sub型のメッセージ通信の仕組みで,BluetoothとかWi-Fiとか非可聴音をうまく使って近辺にある端末を探しだしいい感じに通信させてくれる仕組み. AndroidとiOSで動くようになっていて,相互のプラットフォーム間での通信も簡単にできる.前にAndroid間での通信はしたんだけど,そういえばお布施を払わなくてもiOS実機試せると思い出し,Android <-> iOS通信してみることとした. 本当は気合をいれて解説するとばかうけなんだろうけど,眠いのでとりあえず後日.リポジトリと参考サイトの列挙でとどめておこうと思う.
リポジトリ
iOS版は気合入れてSwiftで書いてみた.ただゴミだと思うので,詳しい人教えてほしい.
APIKeyは,Androidはプロジェクトルートにgoogle_api_key.txt
という名前でファイルを置いておもむろにAPIkeyだけかけばいい.
iOSはソースコード中に書いてあるんのでいい感じに書き換えてくれ.
参考文献
Googleの公式ドキュメントとりあえず読むと良い. Overview | Nearby Messages API | Google Developers
AndroidでのNearby解説.記事内はKotlinで書かれているが自分はJavaで書いた. Android - Nearby Messages APIでチャットみたいなのを作ってみる - Qiita
Android ListViewに関してコードパクった頂きました.ありがとうございます.
灯火: Android : ListView が一番上 / 一番下にスクロールしたかを調べる
AndroidでGoogle API Keyを外部ファイルとしていい感じに管理する方法.gradle便利だなぁ. Manage Google Maps API Key with Gradle in Android Studio - Stack Overflow
iOSでのNearby解説.本当にお世話になりました. Nearby Messages by Swift - ゆずとみかんといちご
battery-historian使ってみた
BatteryHistorianとは2014年のGoogleI/Oで発表されたAndroidアプリにおける電力使用量を詳しく調査するための開発者ツールの一種です.
前置き等はこちらの記事が参考になるかとおもいます.
この記事ではpythonスクリプトという説明がなされていますが,あるとき見るとやり方が変わっていたので,それについてだらだらっと書きます.
battery-historianの公式リポジトリはこちら github.com
基本的にはこのリポジトリのREADMEを参照すれば良さそう.
またBatteryHistorian2.0からはpythonではなく,Golang製になっていました.
Golangそのものの設定はググるといいと思う.GOPATH
だけちゃんと設定していればいい.
ちなみに自分はGOPATH=~/local
にしてる.そうするとそれ以外のソースコードとかも統一して管理できる.
Protocol BufferのGoライブラリを入れる
$ go get -u github.com/golang/protobuf/proto $ go get -u github.com/golang/protobuf/protoc-gen-go
The compiler plugin, protoc-gen-go, will be installed in $GOBIN, which must be in your $PATH for the protocol compiler, protoc, to find it.
protoc-gen-go
というバイナリを使用するらしいので,PATH通しておけとのこと.$GOBIN
設定していればその場所に,してなければデフォルトで$GOPATH/bin
に入るらしい.
改めてREADME読んで$GOBIN
なるものを初めて知った.デフォルトは$GOPATH/bin
らしいから普通の人は気にしなくていいと思う.
Protocol BufferはGoogleが作ってるシリアライズフォーマット.研究室のコードで使われてた形跡とかあったけどあんまり知らない.
Battery-Historianダウンロード
# battery-historianダウンロード $ go get -u github.com/google/battery-historian # battery-historianのディレクトリに移動 $ cd $GOPATH/src/github.com/google/battery-historian # セットアップスクリプトを起動 $ bash setup.sh # Battery-historianサーバ起動 $ go run cmd/battery-historian/battery-historian.go [--port <default:9999>]
あとはgitから落としてきた上で,セットアップスクリプト動かすだけ.
見て分かる通り今回のバージョンからGolangによるサーバが立つかんじらしい.
ここまでできたらlocalhost:9999
にアクセス.
統計データ抽出
あとは開発者モードをオンにしたAndroid端末を用意する.これはググって.
その後adbを利用して
$ adb bugreport > bugreport.txt
として出てくるbugreport.txt
をbattery-historianにアップロードすると解析してもらえる.
bugreport出力は時間がそこそこかかるので注意.
あとデフォルトで取れるデータで記録されないものとかあるらしいので,イカのコマンドで有効にする*1
$ adb shell dumpsys batterystats --enable full-wake-history
bugreport
のリセットはイカのコマンドで.
$ adb shell dumpsys batterystats --reset
データの可視化
無事ファイルをセットできると,こんな画面が見える.
それぞれのパラメータの意味はぶっちゃけ全部分かってない...
参考文献
5分でわかるBatteryHistorianによるAndroidアプリの解析方法 - クックパッド開発者ブログ
google/battery-historian · GitHub
Battery Historian (unofficial) - Google Docs
*1:ぶっちゃけこの操作の意味分かってない.また調べないと...
zshを江添さんっぽくする方法
curlするruboty plugin書いた
書いた
gem: ruboty-http_curl | RubyGems.org | your community gem host
jenkinsのビルド開始とかをrubotyからしたくて,curlコマンド打てるようになりたかったから作った. ついでに,gemsへのアップロードもしてみたかったので勉強がてらやった.
ぶっちゃけ自分でも使いにくい.アップデートはやるつもり.
ruboty-gen
Ruboty の Plugin のつくりかた #ruboty - Qiita
ここを参考にpluginを書きました.ありがとうございます.
rubygems
なんかruboty-genに全部用意されてて,rake releaseってしたらアップロードされた便利.
rubygemsのアカウントつくるのも簡単で,rubygemsのページでアカウント作った後,おもむろにこのコマンドを打てみたいなこと言われるから打ったら認証情報も落ちてきて便利だった.
おわりに
長文書く力なくなってきた.
2015/04/06に解決した問題
今日解決した問題雑に書く.
とあるマシンが再起動時に上がってこないうえsshdも立ち上がってない
マシンのリブート時にNASへのマウントでパスワード求められて止まってた.sshd起動前に止まってたからsshは入れないのにpingは通るみたいな辛い感じだった.apacheのssl鍵とかパスワード付きだと起動時にパスワード求められて止まるのと同じ症状かな.
NASにはcifsでマウントするんだけど,guestでアクセスできればよかったので/etc/fstabにguestでつなげるよう設定を書いた.
/etc/fstabに
//xxx.xxx.xxx.xxx/nas_dir /mnt/mnt_dir cifs defaults,guest 0 0
ってした.
slack移行の準備
slack移行のために通知をslackでも有効にした.物によって通知先変えたいからかなり頑張った.時間があったらジョブを複数指定して指定したジョブの通知をあそこに向けるみたいなプラグイン書きたい.ジョブを分けているとたくさんあって大変*1.今回は手でjenkinsおじさんの通知を全部書き換えた.死ぬかと思った.
jenkinsおじさんのジョブ階層化
jenkinsのジョブが死ぬほどあってスクロールとかもろもろ大変だったので,階層化するプラグイン入れた.
参考文献: blog.fenrir-inc.com
これの
Categorized Jobs View - Jenkins - Jenkins Wiki
Categorized Jobs Viewというのを入れた.正規表現でジョブを区分けもできるので,プロジェクトごとに共通した単語が入っていればプロジェクトごとに分けるのも簡単.