SORACOM APIをC#から触れるようにした

2015年10月16日金曜日

宣伝

.NETからSORACOMのAPIをさらっと叩ける非公式SDKをつくりました。
https://github.com/muojp/SoraCommonNet
気になる点があればふわっとissueに書いて頂けるとうれしいです。
本エントリでは、この開発中に使ったツール類や方法論、より深くSORACOMに触れてみて得たものなどをメモします。

イントロ

届いたSORACOM、さーてどう使おうかなと思って公式の開発者向けWebサイトを眺めていたら「.NET用SDKないじゃん!」と気付いて呆然としたところからスタートしました。せっかくなのでサーバから手元の携帯電話まで、広い環境で動作するプロファイル(PCL)で書くことにしました。
3マスすすむ。

ここまでやった

ひとまず昨晩ごりごりと作って
  • Operatorの新規登録(仮登録メール送信〜登録確認まで)
  • Operatorとしてのログイン
  • トークン更新
  • Subscriber(SIM)の一覧取得
までできるようになったのでNuGetへ投下しました。
逆に
  • Subscriber(SIM)の絞込検索
  • グループ管理
  • イベント管理
あたりはまだ書いていません。
せっせと作り進んでいく途中、Subscriber(SIM)のアクティブ化/非アクティブ化あたりで公式ドキュメント上のTry it out!機能から叩いてもエラーを吐くものをいくつか見つけた時点で一旦心が折れたので実装はそこまでになっています。
あっ、今回はなるべくRuby版のコードは無視して公式ドキュメントのみで書いてみる縛りでやってみました。初見時からときおりドキュメントに怪しい部分があると感じていたのですが、これに沿って実装することで抜け漏れを洗い出せた気がします。

SORACOM Beam開発者の友、Runscope

SORACOM Beamは「SORACOM Airからの通信をソラコムのゲートウェイで受けて適宜プロトコル変換、ヘッダ付与のうえで他のサーバへ投げ直す」という仕組みです。
こう聞くと、どんなヘッダがついてくるのか、署名データはどのようなものなのか気になって実際にサクッとHTTPリクエストのログを取ってみたくなりますね。
しかしまあサーバを立ち上げてリクエストロガーをこさえて待ち受けるなどするのは結構面倒です。
このエリアで「発行されたURLへHTTPリクエストを投げると、その内容を記録して後から調べられるようにしてくれる」というスナックなサービスとしてrequestbinが有名です。
しかし残念ながらrequestbinはHTTPSでのデータ送信をサポートしていないようです。少なくともSSL証明書の真正性検証まわりでエラーを吐くので、ゴリ押しで実行してもデータ送信側サーバのポリシーによっては接続確立させない可能性があります。今回の用途ではひとまず避けるのが無難でしょう。
そういうわけでHTTPSをきちんと通せる代替サービスを探してみました。
https://www.runscope.com/がこの用途にぴったり合いそうです。
14日トライアル後の料金を見ると月$79と結構な額するのでびっくりしますが、実は「トライアル期間後も月間25,000リクエストまでは無料で使えるので安心してね」と書いてあります。
図1 RunscopeでSORACOM Beamの中継結果をダンプ
とても便利ですね。
SORACOMにはsandboxがないので、実際のIMSIなどを含む情報を第三者のサーバへ渡しつつ開発することになるのが嫌な気もしますが、そういう際にはRunscope自身が提供しているrequestbinのソースを使って自前で立てるのが良いと思います。
共有のワイルドカードSSL証明書が導入された環境を用意して…と相応に手間ですが。
MQTTや生TCPプロキシ機能あたりも考えていくと、かしこいBeam対向サーバソフトウェアの需要は一定ある気がしますね(署名検証のみやって既存ソフトへ渡すラッパでも良いはず)。

SORACOM Beam開発者の友、Windows Phone端末(MADOSMA)

WPのデータセンサー機能がなかなか良いよという話です。
SORACOM側でのIMSI付与および署名付与を使うためには、当然SORACOM Airからリクエストを発生させる必要があります。
SIMが刺さっていて、おとなしい(バックグラウンド通信をガンガンしない)環境が必要です。
Androidについてひつじが頑張ってたのでそれで、と思ったのですがたまたま手元にあるAndroid 5.x端末のSIMスロットの調子が悪いので、別解を求めて0.2里というところです。近いですね。
手元にある中でなるべくバックグラウンド通信が静かな端末を探したらMADOSMAだったので、こいつに挿してちまちまとアクセスすることにしました。
さて、Windows Phoneにはデータセンサーという機能があります。モバイルネットワークの通信量を制御したり、バックグラウンド挙動に制限を加える機能です。
Windows Phoneは高速ネットワークが一般的でない地域でのシェアを得るためにか、本機能をなかなかよく作り込んでいます。通信量制限の基本設定をおこなえば、あとはスイッチひとつで基本的にバックグラウンド通信をごっそり遮断できます。システムアップデートの自動ダウンロードも選択式(デフォルトは無効化された状態)なので、気付いたら100MB゚(゚´ω`゚)゚。ピーということが多分ありません。
図2 Windows Phone 8.1のデータセンサー
もちろんiOSなどにも似た機能はあるのですが、iOSの場合は「モバイルネットワーク利用を認めないアプリをひとつひとつスイッチでオプトアウトしていく」という途方も無い作業が必要です。それに、iOSはシステムサービスが相応にデータ通信をおこなっています。
そこで、どのご家庭にもあるMADOSMAの登場です。
今回、SORACOM Beamの動作確認には「Runscopeで発行したURLをSORACOM Beamの転送先エンドポイントとし、SORACOM Beam側エンドポイントURLをいじったら適宜QRコードを生成してMADOSMAで開く」というフローをとりました。
ここでのポイントはMacなどからMADOSMA経由のテザリングアクセスをしないことです。特にMacのMac App Storeなどは「Wi-Fi環境だ!わっほーーーい」という具合に無慈悲なアップデートをおこなったりするので、気付いたらデータ転送量がアホみたいに膨らんだりします。
Macからcurlを叩いてリクエスト検証をしたい場合には(デフォルトルート指定に気をつけつつ)Wi-Fiとは別にBluetoothテザリング経由で携帯端末にアクセスするなどの工夫が必要でしょう*1
[*1] これはUSBドングル形式の3G/LTEモデムを利用する場合でも同じです。接続順などでデフォルトルートを書き換えられないよう、あるいはそれを上書きするように一定注意すればなんとかなるでしょう(そしてたまに事故る)。

APNのプロキシ設定でいい感じに足回り整備できないかの検討

SIMに対するAPN設定欄にはプロキシサーバの設定項目があります。一時期はWeb閲覧高速化プロキシをここに指定することでWebブラウジングが快適になる、という使い方をちらほら見ました。最近は通常事業者側の透過プロキシで処理されるためあまり見かけませんが。
このプロキシサーバ設定で自前のサーバを指定し、不要なアプリの通信やOSアップデートなどのリクエストを遮断できるのでは、という指針です。
おそらく、一定はできると思います。OSのアップデートファイルダウンロードあたりを止められるかはわかりませんが、基本的にアプリケーションのトラフィックを流せるようになりますし。
この場合、プロキシに指定するのは開発者自身が用意したサーバとなります。このためSORACOM Airでこの仕組みを使うと、相応のものを失うことになります。SORACOM Beamが持つ「低負荷なMQTTや生TCPをセキュアなプロトコルに変換しておたくのサーバに届けるよ」というおいしい仕組みを利用できないというつらさです。
beam.soracom.ioへのトラフィックのみプロキシを介さずに処理できれば両立できそうですが、APNへのプロキシ設定に例外ホストを指定できる環境を見たことがないので、多分無理なのではないかなと。
ということで一長一短ありますね。常用しているAndroid端末からのほとんどのリクエストを叩き落とす系の用途には使えそうなので、ネタとしてストックしておいてよさそうですが(相応のプロキシサーバを用意しないとフィルタリングも結構たいへんじゃないかなぁ)。

.NET的な事情

今回書いたライブラリはWindowsサーバ上でもMac上でもAndroid/iOS/Windows Phone上でも動かしたかったので、PCLにしました。
PCLで扱えるREST APIへのアクセスライブラリは割とどれも一長一短あるのですが、PortableRestを使いました。これは、以前Pivotal Trackerへのアクセスライブラリに手を入れた際に試してみて「完全ではないけれど事足りる」とわかっていたためです。
PortableRestの厄介なところは概ね以下のとおりです。
  • ステータスコードを取得するのが結構大変
  • エラー(4xx、5xx)が戻ってくると容赦なく例外を吐いてレスポンスボディを捨てるので「400を返しつつヒント情報をレスポンスボディで戻す」ようなAPI(SORACOMもこれ)との相性がかなり悪い
ドキュメント(たまに間違ってる)を読みながらゴリゴリと実装していくパターンとの相性は、あまりよくありません。PortableRestは1年以上バージョンアップが止まっているし、そろそろこのライブラリ自体に手を入れたほうが良いのかもという気もしています。
ちなみに
  • multipartリクエストにおいて複数ファイルのアップロードをサポートしていない
という問題もあるのですが、SORACOMのAPIを叩く分には関係ありません。

作ってる途中で見つけたドキュメントの怪しい点

そもそもSDKドキュメント内のTry it out!から叩いても普通にエラーを吐くAPIがある

たとえば/subscribers/{imsi}/enable_terminationで、IMSIを指定して実行するとサーバが400を返してきます。
{
  "code": "SEM0003",
  "message": "Bad request: Invalid Json"
}
という具合です。
  • /subscribers/{imsi}/disable_termination
  • /subscribers/{imsi}/activate
  • /subscribers/{imsi}/deactivate
あたりも同様です。
どうもJSON本体を持たない系リクエストが失敗している風味があるので、ひょっとすると空ボディでも食わせればうまくいくのかもしれません。
おそらく実装的にはRuby版SDKの中身を読んでそれに合わせるのが手っ取り早いです。

/subscribers/{imsi}はドキュメントに記載されている項目よりもたくさん値を返してくる

以下が増えていました。ドキュメントを書いた後で増えたのかもしれません。
  • groupId
  • terminationEnabled
  • sessionStatus
  • moduleType
  • plan
なお、ドキュメントされていないsessionStatusは未使用SIMではnullを返します。そのSIMを使い始めた後には戻ってくる値が変わり、ネストした要素でimeiなどの値を持つようになります。
登録済み・未使用状態のSIMを使ってSDK開発をおこなっている際には気付かず、後から念のためテストを一回しした際に見つけて「ヒッ」となりました*2
[*2] その後、ひとまずhttps://github.com/muojp/SoraCommonNet/commit/09e8c9037でワークアラウンドを入れました。じきにちゃんとスキーマを書くと思います。

/operators/{operator_id}/token の戻り値がドキュメント記述と異なる

ドキュメントには
GenerateTokenResponse {
  apiToken (string, optional)
}
と書かれていますが、実際はtokenというキーで戻ってきます。しばしハマりました。
追記(2015/10/29): 10/27のドキュメント改訂で直っていました

作ってる途中で湧いた疑問

ちょうど今日SORACOM Developers Conference #0があるので、そこで聞こうという備忘録も兼ねてメモ。
  • Beamでtcpを使った場合、課金用のカウントはどのようになる?
    • パケット数でカウント?HTTPはリクエスト単位?戻りがchunked-transferとかなったらどうなる?
  • SORACOM BeamでIMSI ヘッダ付与署名ヘッダ付与として事前共有鍵を指定した場合の署名検証の方法
    • X-Soracom-Signatureを見る限りはHMACSHA256っぽいけれどさすがに値の食わせ方が分からないとムリなやつでは
    • key=<事前共有鍵> imsi=<IMSI> timestamp=<Timestamp>などいくつか試してみたけれどハズレだった
      • TCP→TCPなど、リクエスト全体が事前に分からない場合でも(おそらく同じ手順で)署名検証できるということは基本的に事前共有鍵+ヘッダ内の情報のみで計算できるはずなのだけど
  • /operators/{operator_id/token}のtimeout_seconds、元トークンよりも長い設定をしても受けない(つまりauth時に指定した間隔以下でしか受け付けない)ようになってたほうがセキュリティ的には都合よいのでは?
X-Soracom-Imsi: 11112222XXXXXXX
X-Soracom-Signature: 31XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXf4
X-Soracom-Signature-Version: 20150901
X-Soracom-Timestamp: 14449XXXXXXXX

作ってる途中で湧いた要望

書いているあいだじゅう、sandboxがないのでTermination(SIM解約)コマンドとかほいほいとテストできないことがとてもつらかったです。
ということで、いくつか要望をまとめました。これも今日のSORACOM Devel(ry
  • sandboxがほしい
  • sandboxがほしい
  • sandboxがほしい
  • Subscriberの無効化とかは適当にイベントAPIから流してほしさがある(完全性確保は求めないとしても)
    • 加えて、イベントはInvokeAWSLambdaAction以外に普通のHTTP/Sキックをできてほしい…諸々Azureに流したいけどプロキシだけのLambda書くのも嫌な感じ
      • これができると、Azure上で指定容量到達イベントを受け取ってSubscriberをdeactivateするような仕組みをさらっと作れて嬉しい
  • Beam専用モード(Beamのエンドポイント以外への通信を遮断するモード)がほしい
  • BeamのログをS3のバケットにスロッシュしておいてほしい
  • サーバ上で走り続けるプログラムからアクセス元SIMのIMSI検証などをおこなうことを考えると事実上サーバへのID/パスワード保存が必須(トークンを延長し続けていってエラーを吐いたら詰むため)。できればアプリケーションキーなどの権限委譲機構が欲しい
    • 難しいようなら、Operatorの親子関係を作って子側(最悪の場合無効化すればいい)のID/パスワードをサーバへ保存するワークフローを望む

0 件のコメント:

コメントを投稿