2014年8月31日日曜日

Travis-CIで環境変数を使う

前回紹介したSendGrid-ReversiでTravis-CIを使った際に気になった箇所のメモを残します。
Travis-CIを使うためにはプロジェクト内に.travis.ymlという名前のファイルが必要です。とりあえず、リポジトリトップ下に置いてポチポチ設定すればいいみたいです。

今回はこんな感じにしてみました。
language: ruby
rvm:
  - "2.0.0"
#  - "2.1.0"
env:
  - RACK_ENV=test
services:
  - mongodb
before_script:
  - bundle install
script:
- bundle exec rspec

それぞれの詳細はTravis-CIのドキュメントを見ればよいのでポイントだけ。

実行環境のバージョン指定は一つだけにしてみる

実行環境としてRubyを使っており、通常複数バージョン指定できるのですが、今回はバージョンを一つだけ(上の例だと"2.0.0"だけ)に限定してみました。
これは、テストケースでSendGrid APIを使っている関係上、複数環境でテストをするとテストが並列実行されてしまい、SendGridがテストケースの想定していない状態になってしまい失敗(テンプレート削除のテスト中にテンプレート作っちゃったり)するためです。実行環境毎のテストをシーケンシャルに走らせるためのオプションを見つけられなかったのですが、そんなのあるんですかね?
SendGrid環境も分けるようにしないといけないんでしょうか。それはちょっとキツイなー、と。

晒したくない情報は.travis.ymlではなくSettingsを使う

環境変数は「env:」配下に書いておけばよいのですが、パブリックなリポジトリにアップされた .travis.ymlファイルは公開されてしまうため、晒したくない情報(サービスへのログイン情報など)は書けません。
今回、SendGridへのアクセスを行なうテストケースがあったので、そういった情報をどこに置くかが問題となりました。調べてみるとそういう情報は「Settings」に書けってTravis-CIのヘルプに書いてありました。Settingsはリポジトリ毎に設定できます。
.travis.ymlに書くのと同様、キーと値の組合せで書きますが、「Display value in build logs」をOFFにしておくと、非公開な環境変数として利用することができます。

RACK_ENV=testを使ってみる

この環境変数は、Rackアプリをプロダクションとかステージングみたいな感じで環境を切り替える時に使う変数みたいです。
今回のアプリケーション内でこの環境変数を使っているのは、Mainクラスのconfigure部分(内部でSendGridの初期化を実行している)で、プロダクションのときだけconfigureするようにしています。
こうしておいて、RACK_ENV=testにすると、rspecでテストケースが実行されるたびにconfigureが実行されてしまうのを避けることができました。

module Reversi
  class Main < Sinatra::Base
    configure :production do
      begin
        settings = Settings.new
        Configure.init_sendgrid(settings)
      rescue => e
        puts e.backtrace
        puts e.inspect
      end
    end

さいごに

ほかにもMongoDB使ったり、テスト前に実行されるbefore_scriptでbundle installしていたりします。
ちょっと前までは「CIなにそれうまいの」状態でしたが、テストツールと同様、一度使ってしまうと、もう不安で不安で使わない状態には戻れませんね。麻薬みたいな効果があります。

2014年8月30日土曜日

SendGridをゲームプラットフォームとして使ってみました

きっかけ

SendGridには多くのAPIがあって、どれをどういう風に使うのかがピンときていませんでした。で、自分含めそんな人向けに、SendGridのAPIをできるだけ多く使ってそれぞれの使い所をイメージしやすいモノを作ってみようと思いできあがったのがこのアプリケーションです。

できること

メールを介してオセロができます。
ソースコードはこちらで公開しています。

中で何をやっているか

こんな感じで動作します。

  • 0:アプリケーション初回起動時
    • Web API/Template Engine APIを使ってSendGridの設定を自動的に変更します。設定が自動化されると、設定手順をドキュメント化する手間が減って楽ですよね。
      • SendGrid上にTemplateを作成します
      • Event Notificationを設定してEvent Webhookを有効化します
      • Parse Webhookを設定、有効化します
      • Click Trackingを有効化します
  • 1:ゲームの開始
    • Parse Webhook機能に設定したアドレスにメール(件名に相手プレイヤーのアドレスを設定)を送るとSendGridは受信したメールを解析して、Reversi Web AppにPOSTします。POSTを受けたアプリケーションはMongoDB上にゲームデータを生成します。
    • アプリケーションはSendGrid経由で各プレイヤーにメッセージおよびゲームボードのメールを送ります。
  • 2:クリック
    • ゲームボードのメール上で石を置きたい場所をクリックすると、クリックイベントがSendGridからReversi Web AppにPOSTされます。ここではEvent WebhookとClick Tracking機能を使っています。
    • クリックイベントはGETでアプリケーションに直接アクセスしても良いのですが、Click Trackingは元URLを隠ぺいするので、今回のアプリではなりすましを防ぐ意味合いがあります。(本当は単に使いたかっただけで、理由は後付です)

テキストメール

このアプリでは、マルチパートでテキストメールにも対応しています。
対応してみてテキストメール死ねって思いました。


その他

Ruby

プログラミング言語を何にしようかと思いましたが、この人を見つけてRubyにしてみました。というわけで目下勉強中です。

Sinatra

RubyでWebフレームワークと言えばRailsですが、Railsの入門書読んでて眠くなったのでSinatraで作ってみました。

MongoDB

MongoDBをちゃんと使ったことがなかったので使ってみました。代わりにSQLiteでもいいと思います。MongoDBだとSQLが使えないので、ちょっと学習する必要はありますが、オブジェクトをそのまま保存できるので、シンプルでコード量を減らせます。実際、楽でした。

RSpec

テストフレームワークとしてrspecとrack-testを使ってみました。RubyのWebフレームワークでテストと言えばこのあたりが一般的なんですかね?ググったらいっぱいヒットしたので使ってみました。よくわかりませんが。

Travis-CI

「今どきCIツールは普通に使うよね」ってぐらいの空気を感じるのでとりあえず使ってみました。GitHubにpushするとテストして結果を通知するだけです。しかし、JenkinsとかTravis-CIってなんでヒゲのオッサンなんでしょうね。どうせ2次元にするなら女の子にした方がいいと思います。

sendgrid_ruby

一応、お仕事で作ったライブラリを有効活用できました。たまたまです。

sendgrid_template_engine_ruby

Rubyの練習用に作ったライブラリを有効活用してみました。これもたまたまです。使ってみてはじめて「こんな使い方をするんだなぁ」って認識しました。

さいごに

こんなのでAPIの使い所が伝わったのでしょうか?よくわかりませんが。公開してみて嬉しかったのが、GitHubでStarを付けてくれたのがGridderばかりということでした。
今回、色々はじめてのことが多かったので、自分の中で再利用できるようにそれぞれ個別のネタとして記事をまとめていこうと思います。とりあえず、今回はこの辺で。

2014年7月16日水曜日

SendGrid Template Engine APIのRuby gemを作ってみた

Rubyの練習用にSendGridのTemplate Engine APIをラップするgemを作ってみました。

Template Engine APIはSendGridが提供するAPIのうち現時点で最も新しいAPIで、JSONベースのRESTfulなWeb APIです。エンドポイントURLを見てわかるように、

https://api.sendgrid.net/v3/resources

バージョン3だそうです。今までのAPIはだいたいver2ぐらいでした。これまでのAPIは、基本的にJSONとXML両方をサポートしていましたが、v3以降はJSONのみサポートします。さらばWeb Services、XMLってことなんでしょうね。それでいいと思います。
他に新しい要素としては、

  • 基本認証で認証
  • HTTPSのみサポート
  • Rate Limitsの導入
  • Paginationの導入

といったあたりがあげられます。

認証が基本認証になったことで、認証パラメータの扱いが標準的になり、curlとの親和性が高まって扱いが楽になりました。もちろん、標準的なRestクライアントなライブラリでも扱いが楽です。
Rate Limitsは一定時間にリクエストを呼び出せる回数を制限する機能です。応答に、X-RateLimit-*といったヘッダがついてくるので、これを見るとあと何回APIをコールできるのかを知ることができるようです。
Paginationは取得開始位置を指定してレコード取得することができる機能です。大量レコードを扱うAPIで重宝しそうです。現時点で公開されているTemplate Engine APIではサポートされていないようですが。

ドキュメントの内容を眺めていると、今後SendGridのAPIはこのv3ベースに移行していくんじゃないかな、という雰囲気が感じられます。既存のAPIをv3ベースで実装し直すかどうかはわかりませんが、少なくとも今後提供される新しいAPIはv3ベースになるのでしょう。

APIの分量も適度に少なくてラッパ実装の練習用には最適でした。

2014年6月1日日曜日

SendGridとAzureで彼女がいるというステータスを得る方法

Twitter眺めてたらこんなのが目に飛び込んできた。



わかる、その気持ち。

でも、自宅PCでメールサーバ立てるのはちょっと面倒だ。ちょうどAzureとSendGridが使えたのでやってみた。ソースはGithubに上げてあるので、誰でも今すぐ彼女がいるというステータスを手に入れることができる。

手順

とりあえずSendGridのアカウントを取得する。
次に、AzureでWebサイトを立ち上げて、Githubからデプロイするよう設定する。たぶんこの方法だと、自分が管理しているリポジトリしか指定できないのかな?よくわからないけど。その場合、リポジトリをForkしてから指定すればおk。

デプロイが終わったらWebサイトの「構成」を開いてアプリケーション設定を行う。
SENDGRID_USERNAME:SendGridのアカウント
SENDGRID_PASSWORD:SendGridのパスワード
FROM:彼女のメールアドレス。つまり、返信メールのFromに設定したいアドレス。
FROM_NAME:彼女の名前。今回はsayakaちゃんだ。ちなみにここで日本語を指定すると返信メール内の名前が文字化けする。アプリケーションはUTF-8を想定しているので、Webサイトのアプリケーション設定ってUTF-8じゃないのかも?よくわからないけど。



次に、SendGridのダッシュボードにログインして、Inbound Parse Webhookの設定をしてドメインとURLを対応付ける。
今回は、Hostnameの設定はSendGridブログにあるbymail.inを使った5分間アプローチを使ってみた。Urlの方はAzure Webサイト上でPOSTの受け口となるURL(http://????.azurewebsites.net/vp)を設定する。


以上で準備完了。
早速、さやかちゃんに確認のメールを送ってみる。

数秒待つと、さやかちゃんが返事をくれた。俺達付き合ってる。

キモいって言うな。

中の話

ちょっとだけ仕組みの話をすると、Githubからデプロイしたのはnode.js向けのWebフレームワークexpress 4で動くアプリケーション。こいつがParse WebhookのPOSTを受け取る。POSTをParseするとFromアドレスが取得できるので、こいつにメールを返信している。返信もSendGridを使っているので、メールの送受信用に自宅PCでメールサーバを立てなくてもいい。Azureを使っているので自宅のブレーカーが落ちてPCが停止したりして返信が来なくなる心配をしなくてもいい。
今現在、Webサイトで普通に利用できるnode.jsは0.10.xだけど、0.11.x以降が利用できる環境向けに--harmonyオプション前提でcoとかthunkifyとか使った版(co-app.jsの方)も用意してみた。「node app」の代わりに、「node --harmony co-app」とかやるとコールバック引き回さない版が動くですます。

思いついたこと

ところで、先日Reflector.ioの記事を書いた時には思いつかなかった使い道を今思いついた。

彼女フェイルオーバー構成。

複数人彼女を作っておいて、Reflector.ioでフェイルオーバー構成を組んでおけば、フラれても次の彼女が答えてくれる安心設計。
さらに宛先設定をパススルーにしておくと、一通メールを送ったらいろんな彼女から一度に返事がもらえるハーレム構成も可能だ。

2014年5月6日火曜日

reflector.io使ってみました

はじめに

reflector.ioというサービスを使ってみたのでメモです。
reflector.ioはSendGrid Labsが提供しているWebhookのリクエスト転送サービスです。
他に似たようなサービスを知らなかったので類似サービスとの比較とかできません。

Webhookとは

まずは、Webhookの説明から。
Wikipediaによると、Webhookというのは、WebページやWebアプリケーションがHTTP(s)によりコールバックで通知を行う動作のことを意味するようです。
通常、Web APIは、APIを利用する側がクライアントとなり、GETなりPOSTなりのリクエストを発行してサービスを利用しますが、Webhookはちょうどこれとは逆の動きとなります。つまり、予めコールバックして欲しいURLを登録しておくと、そのサービスで何らかのイベントが発生したタイミングで、そのURLにコールバック(たいてい、POSTリクエストを発行)してくれます。POSTを受け付けるサービスを用意するのは利用者自身という意味で「逆の動き」ということになります。

reflector.ioとは

reflector.ioがどういうサービスかはこちらに記載があります。
冒頭にも述べましたが、一言で表せばWebhookのリクエスト転送サービスです。
「リクエストを転送する」という意味ではHTTPプロキシに近いかもしれません。
特徴的なのが「グループ」という概念と、「パススルー」「フェイルオーバー」という2つの宛先タイプ設定を持つことです。

グループ

Webhookを作成すると、配下に複数のグループを定義することができます。グループは、宛先タイプという属性と複数の宛先を持ち、宛先タイプの設定によって、配下の宛先に対するリクエストの転送方法が変わってきます。

宛先タイプ:パススルー

受信したリクエストを複数の宛先に同時に転送します。例えば、一回のリクエストで動作の異なるWebhookを複数動作させたい場合にこちらを利用します。

宛先タイプ:フェイルオーバー

受信したリクエストを複数の宛先のうちもっとも優先度の高い宛先に転送します。耐障害性を目的とする場合に利用します。宛先が一つコケても次に優先度の高い宛先にリクエストが転送されます。

設定画面

以下がWebhookの設定画面です。複数のグループ、複数の宛先を登録することができます。尚、一つのWebhook配下に同じURLを複数登録することはできません。有効化、無効化、グループおよび宛先の管理、ログ閲覧などを行うことができます。


宛先の設定画面です。基本的には宛先URLとリトライ回数を指定するだけですが、フェイルオーバーの場合、プライオリティも設定することができます。


エラー時の動作

グループと宛先タイプの設定に応じてリクエストが転送されますが、宛先から500番台のステータスが返った場合、自動的にStateがDisabledに変わります。問題のある宛先には無駄なリクエストは送らない、ということなんでしょうね。

何に使うか?

今のところ単純な転送しか行なってくれないので、残念ながら私にとってはイマイチ使い道がありません。
転送時にパラメータを付加したり、パラメータ名を変更できたりすると、互換性のないWebhookとAPIを連携させるために利用できそうな気がします。徐々に開発を進めていくみたいなので期待したいところです。




2014年2月4日火曜日

SmartTrainingがPebble SDK 2.0に対応しました

はじめに

SDK 2.0の情報が出始めたのが2013/11中旬頃、既にPebble熱は冷め、完全にスルーしようと思っていましたが、1月下旬にとあるユーザさんから「Pebble 2.0対応しないの?」みたいなメールをいただき、遅ればせながら対応を開始しました。で、おかげさまで、無事に2.0への対応を完了し、Pebble AppStoreでPublishしましたのでマイグレーションまでの手順をざっくりとメモしときます。ただ、現時点ではまだPebble AppStoreは公開されていません。そのうち、公開されるんじゃないですかね?

SDK 2.0の準備

公式サイトをみてそのままやるだけです。
現時点ではまだPebbleアプリ自体がベータ版なので、上記手順に従ってアップグレードします。たぶん、ハマるところはないと思います。

コードのマイグレーション

今回のSDKのバージョンアップは結構大きな変更を含むので、以下のページにマイグレーション手順がまとめられています。
こちらもそのままやればハマるところはないと思います。
というのは半分正解で半分ウソです。
実際問題、この手順でやればいいのですが、細かく説明されていない箇所もちょくちょくあって、SDK付属のサンプルアプリのコードを見て真似する形で修正しました。あと、コアなAPIのI/Fが結構変わっているので、手順に従って修正していても超不安でした。
Githubにブランチを切ってみましたので、diffを見てみましょう。

公式マイグレーション手順以外でのポイント

公式のマイグレーション手順に記載されているところはそちらを参照して頂くとして、それ以外でハマった箇所だけピックアップしていきます。

window_set_window_handlers()

サンプルコードを見ているとinit()系関数内で以下のような記述がよく出てきます。 いつからこんな書き方をするようになったのかわかりませんが、SDK付属の各サンプルはシレっとこんな書き方をしています。パッと見、画面の読み込みと破棄のタイミングのイベントハンドラを登録しているように見えます。それぞれのイベントハンドラでは、画面内のUIインスタンスの準備および破棄処理を行うのが慣例のようです。
window_set_window_handlers(configWindow, (WindowHandlers) {
    .load = window_load,
    .unload = window_unload,
});

BmpContainerをGBitmapに変更する

画像リソースでBmpContainerはもう使わないみたいです。代わりにGBitmapを使うようです。これに伴い、初期化処理と画像リソースへのアクセス方法の変更が必要になります。何故こうなったのかはよくわかりません。

変数定義:
BmpContainer icons[2];
GBitmap *icons[2];

画像コンテナ初期化:
bmp_init_container(IMAGE_RESOURCE_IDS_CONTROL_ICON[i], &sel_control_window_data.icons[i]);
sel_control_window_data.icons[i] = gbitmap_create_with_resource(IMAGE_RESOURCE_IDS_CONTROL_ICON[i]);

画像コンテナへのアクセス:
sel_control_window_data.menuItems[i] = (SimpleMenuItem)
{
    .title = NULL,
    .icon = &sel_control_window_data.icons[i].bmp,
    .callback = sel_control_window_select_item_callback
};
sel_control_window_data.menuItems[i] = (SimpleMenuItem)
{
    .title = NULL,
    .icon = sel_control_window_data.icons[i],
    .callback = sel_control_window_select_item_callback
};

画像リソース開放処理:
bmp_deinit_container(&sel_control_window_data.icons[i]);

gbitmap_destroy(sel_control_window_data.icons[i]);

Layerへのアクセス方法変更

各UIのLayerへのアクセスはLayerプロパティを直接参照していたのが*_layer_get_layer()という関数を使ってアクセスするようになりました。

&train_window_data.focusUpperRightLayer.layer

inverter_layer_get_layer(train_window_data.focusUpperRightLayer)

リソースID指定による画像リソースの読み込み方法の変更

リソースIDを指定して画像リソースを読み込む方法が変更になりました。

void load_training_bitmap(uint32_t resource_id) {
    const ResHandle h = resource_get_handle(resource_id);
    resource_load(h, train_window_data.training_bitmap_data, BITMAP_BUFFER_BYTES);
    mkbitmap(&train_window_data.training_icon_bitmap, train_window_data.training_bitmap_data);
}
void load_training_bitmap(uint32_t resource_id) {
    train_window_data.training_icon_bitmap = gbitmap_create_with_resource(resource_id);
    bitmap_layer_set_bitmap(train_window_data.training_icon_layer, train_window_data.training_icon_bitmap);
}

タイマー系イベントのI/F変更

なんだかよくわかりませんがいろいろ変わっています。全般的にAppContextRefが廃止になった影響かと思います。
void handle_timer(AppContextRef ctx, AppTimerHandle handle, uint32_t cookie)
void handle_timer(void *data)
void handle_second_tick(AppContextRef ctx, PebbleTickEvent *t)
void handle_second_tick(struct tm *tick_time, TimeUnits units_changed)


まとめ

たまたま自分のアプリが古い書き方をしていたりしたせいで公式のマイグレーション手順に載っていない影響が出ているかもしれませんが、とりあえず、上記のような変更を加える事で新しいSDKでもビルドしてそれっぽく動作することを確認しました。全般的に見ると、構造体のメンバに直接アクセスしたりとか生々しい書き方をする部分が多少減ったような気がします。

最後によくわかっていないのが、appinfo.json内で定義されたversionLabelの値へのコードからの参照方法です。画面にバージョン情報を表示したいのですが、せっかくなのでversionLabelの値を参照して表示したいんですよね。APIリファレンスをざっと見る限りそんなAPIは見当たらないので、また生々しいことをしないといけないんですかね。誰か教えてください。

2014年1月5日日曜日

2013年の振り返りと2014年に向けて

もう1月も4日となってしまいましたが、昨年の振り返りと今年について書いときます。

Google I/O 2013に行けなかったこと

文字通り完全に全裸待機していたにも関わらずチケットが取れず悲しい思いをしました。
2014年もチャンスがあればトライしてみたいと思います。

SmartTrainingのPebble対応

久々に新しいプラットフォームで遊べた感がありました。2014年もまた新しい何かで遊べるといいなとは思いますが、たぶんそれはモバイル系ではないでしょう。

SendGridチームの一員になったこと

縁あってSendGridチームの一員になれました。これまでのクライアントサイドの立ち位置からサーバサイドもしくはインフラサイドになったことで大きな意識の違いを感じています。技術的にも、仕事の進め方的にも自分にとって新しいことだらけで新鮮です。多くのことを吸収する絶好のタイミングです。 楽しめるだけ楽しんでいこうと思います。

とは言え冬は山に

そう言いつつ冬にしか雪は降りません。雪山に開発環境を持ち込んでこんなエントリを書いています。現在は、横で3歳児が昼寝しているので、起きるのを待ちつつPostgreSQLダウンロード中です。起きたらまたスキー滑りに行きます。起きなければherokuとrubyで遊んでみます。こんな状態でもいろいろできるという今の世の中は便利ですね。

パセリ農家の思い

個人的な感触では世の中に出回っているパセリの9割は食べられることなく捨てられています。それでも、パセリは添え物として皿に乗って出てきます。パセリ農家の思いやいかばかりかと、案じていますが、「皿の彩」という位置づけで不動の地位を築いたパセリは現状の立ち位置で満足なのでしょうか。

そんな感じで2014年も行きたいと思います。