読者です 読者をやめる 読者になる 読者になる

アラタナエンジニアブログ

aratana Engineer's Blog

Golang と Pushbullet で各種端末に通知をとばすコマンド書いた

Golang Tools CLI

アラタナエンジニアの 光瀬 です。先日まで馬の肉に抵抗があったのですが、アレめちゃくちゃうまいですね。人生損してました。これから挽回して馬刺食べまくります。

さてさて、ふと思い立って Pushbullet HTTP API を叩くコマンドラインツールを書いたので、そのお話をします (まったく、お仕事関係ないですね!)。Golang で実装したので、その辺りについても少しだけ。

長い処理の終了を待っているときにありがちな話

大量のファイルを処理するスクリプトを走らせていると、以下のようなことがよくあります。

  • 処理がいつ終わるのか気になって確認すると、その間別の作業に集中できない。
  • 確認しないと、万が一途中で死んでいたとき、「実行時間 + 気がつくのに遅れた時間」が無駄になる。

いつ終わるのだろうかと、本当に気が気でないですよね。

終了のタイミングでメールを飛ばしてもいいですが、メールの中に通知が紛れ込むのって精神衛生上よろしくないです。あるいは、今風に Slack に飛ばすほうがもっとよさそうです。ただ、チームならともかく、ひとりだと Slack 自体を持て余す感じがしていて、なんだかなあと思っていました。

そんなわけでサイズ感的にちょうど良さそうな Pushbullet というサービスにシェルから通知を飛ばしてみます。

Pushbullet で端末間の連携・通知が便利になる

Pushbullet 使ってますか?Pushbullet は、PC やスマートフォンタブレット間でのデータのやりとりや通知が大変便利になるサービスです。先月 Apple 端末一式に対応して Engadget などでも話題になっていました。Pushbullet では、だいたい次のようなことができます。

  • ある端末から別端末へメモやファイル、URL を別の端末へ共有する。
  • スマートフォンタブレットに届いた着信やメールの受信など各種通知を PC にも通知させる

ほとんど設定しなくても便利に使えるので、非エンジニアにこそ使って欲しいと思っているサービスの一つです。また、最近の話題だと、スマートフォンで受信した各種メッセージアプリの通知を、デスクトップで受信して、そのままスマートフォンに触れずに Pushbullet のみで返信ということもできるようになったようです。

Golangコマンドラインツールを実装する

コマンドラインツールを書く上での Golang のいいところ

実装するのに使う言語には Golang を選びました。Golang の絶妙ないい加減さ、バランスが好きです。ただ、今回は言語仕様的な点には触れません (自分が言いたいことはだいたい他のブログで語られているので)。

コマンドラインツールを書くことにフォーカスすると、Golang の特徴は次の三点あたりでしょうか。

  • とても簡単なクロスコンパイル *1
  • 静的リンクして、ランタイム込みの単一バイナリを吐く。
  • 使い勝手が良く充実した標準ライブラリ*2

これらの特徴のおかげで、実行環境をそこまで意識せず、バイナリ丸投げな配布でやってけるところが素敵ですね。ツール配布時に環境構築で導入失敗する事例が少ないのは大きなメリットです。

逆に欠点ともいえるのは、バイナリが大きくなりがちなことでしょうか。とはいえ、たかだか数 MB なことがほとんどなので、2015 年を生きる我々には大した問題ではありませんね。

コマンドライン引数の処理、サブコマンドの実装

標準でも flag というパッケージが提供されていますが、もうすこしリッチなインターフェイスをお手軽に作成したいので codegangsta/cli を使います。コマンドライン引数の解析、ヘルプメッセージの整形、サブコマンドなどなどイイカンジにやってくれます。

だいたい以下の様な感じでコマンドを記述します。

やらないといけないことは、だいたい下記のとおり。

  1. cli.NewApp でメインコマンドになる *cli.App な値を作る。
  2. メインコマンドに *cli.Command で定義したサブコマンドを追加する。
  3. 各サブコマンドと *cli.Context を引数にとる Action を紐つける。

各 Action が、*cli.Context な引数からコマンドライン引数を取り出して、
対応するサブコマンドの具体的な処理を行うことになります。

なお、今回は利用しませんでしたが、 tcnksm/cli-init という codegungsta/cli を利用したコマンドのひな形を、サッとつくるツールも存在するのでこちらもお勧めです。

高速にGo言語のCLIツールをつくるcli-initというツールをつくった | SOTA

Pushbullet 経由で通知を飛ばす bullet コマンド

前置きが長くなりましたが、 Pushbullet HTTP API 経由でテキストやリンク、ファイルを各種端末に飛ばすコマンドラインツールつくりました。Golang と前述の codegangsta/cli を利用しています。


下準備

ではでは、インストールして使ってみましょう。

OSX かつ Homebrew なユーザーの皆様は以下のコマンドでインストールできます。

$ brew tap mitsuse/bullet
$ brew install bullet-cmd

それ以外の方は、こちらからバイナリを落としてパスの通ったところなど、お好みの場所に配置してどうぞ。

bullet を叩けるようになったら、アクセストークンの設定が必要です。
bullet のサブコマンドは環境変数 BULLET_ACCESS_TOKEN に設定された文字列をアクセストークンとして利用します。

$ export BULLET_ACCESS_TOKEN="<access token>"

自アカウントのアクセストークンは Account Setting から取得できます。

使い方

さっそく通知を飛ばしてみます。 単純なテキストは `bullet send -t {title} -m {message}` で送信します。

$ bullet send -t "もし叶うのならば猫を飼いたい" -m "黒猫であればなおよい"

これで、Pushbullet に紐つけている端末に一斉に通知が飛びます。

特定の端末にのみ通知を飛ばしたいときは、`d オプションに端末名を指定します。

bullet send -d "russianblue" -t "もし叶うのならば猫を飼いたい" -m "PC にだけ通知してみた"

なお、端末名の一覧は, bullet list で取得できます。

一緒にファイルやリンクも送信したい場合は、-l オプションでファイルパスあるいは url を指定します。

$ bullet send -t "mitsuse/bullet" -m "今回つくったツール" -l "https://github.com/mitsuse/bullet"

ちなみに Pushbullet API Documentation の Pushes をみると、
通知にも種類があることがわかります。今回利用したのは、note, link, file の 3 つですが、他にも地図への検索クエリを紐付けた address, チェックリストを作成する checklist という通知のタイプもあります*3

応用

コマンドラインツールなので、他のコマンドと合わせてゴニョゴニョしやすいのがいいところですね。たとえば、以下のような使い方がありそうです。

  • 環境変数、他のコマンドの実行結果をメッセージに埋め込んで送信する。
  • 何らかの処理 (ベンチマークなど) の終了時に得られたログを送信するなど。
  • 長い処理をするスクリプトで、最後に bullet を叩いて終了を通知する

色々できそうなので、使い方を模索してみるのもおもしろいかもしれませんね。

感想

このくらい小さなツールなら cURL + jq とかで頑張っても良さそうですが、それもそれでつらそうです。コンパイラが叱ってくれたほうが、やっぱり安心感がありますし。

まとめ

Pushbullet HTTP API を呼び出すコマンドラインツール bullet を実装して、その紹介をしました。Golangコマンドラインツール書くのにも便利なので、次に書くコマンドラインツールGolang で書いてみてはどうでしょうか。

ではではみなさま、Pushbullet で良い通知ライフ、Golang で良いコマンドラインライフを!

*1:GOOS=linux GOARCH=amd64 go build hoge.go と言った感じで環境変数を設定するだけ。この辺りが参考になります http://qiita.com/Jxck_/items/02185f51162e92759ebe

*2:標準ライブラリ一覧は、こちらから見ることができます。

*3:この address と checklist を、あえてシェルで触るのはコレジャナイ感があったので、bullet では対応していません。bullet の実装で作成した pushbullet パッケージには address, checklist を送るメソッド自体は実装してあります。