ReactNativeのAsyncStorageをNodeのREPLから操作する
背景
ReactNativeにはAsyncStorageというkey-valueストレージシステムがある。 valueにはstringしか入れられない本当に簡素なものだけど、JavaScriptのプレーンなオブジェクトはJSONにシリアライズ可能であるので、さほど困らない。
クライアントサイドで永続化したい情報はAsyncStorageに突っ込んでおく。アプリケーションを作っている過程において、値を少しづつ変更しながら開発を進めたい場面が結構あった。
ところでRailsにはrails consoleというものがあり、railsアプリケーション内のinitialize処理を通した後のREPLを立ち上げることができる。このREPLでは、railsアプリ内のクラスはすでにロード済みであるため、その全てを呼び出すことができる。その中でデータベースアクセスを担うクラス群も呼び出せるため、rails consoleから自由にデータの参照や改変を行える。
普段Railsで開発していることもあり、そんな感じにNodeのREPLからReactNativeのAsyncStorageにアクセスしたいな〜、と思ってそんなツールを作った。
動作
このアプリケーションは、コメントの投稿と同時にAsyncStorageと同期し、コメントリストを永続化している。 REPLからAsyncStorageにコメントを追加し、その後アプリケーションをリロードした時に、コメントが追加されていることを確認している。
仕組み
NodeとReactNativeとの通信はwebsocketを利用している。(ReactNativeは標準でwebsocketをサポートしています。)
REPL起動時にchild.spawnで子プロセスとしてwebsocket serverを立ち上げて、ReactNativeアプリケーションからのレスポンスを受け取る。 REPLのプロセスとwebsocket serverはプロセス間通信を行う。 通信のイメージは以下
データフローの最後の部分で、websocket serverが結果をファイルに書き込み、それをREPLのプロセスで監視しているところがある。なんで??感がすごい。
今回の構成ではWebSocketを挟んでいたり、そもそもAsyncAtorageはその名の通り非同期なAPIを提供していたりするので、REPLから発行したコマンドがAsyncStorageのAPIを叩いて結果が返るまでは、どう頑張っても非同期処理になる。これを無理やり同期処理にするために、ここでファイルを見ている。
REPLで操作しているのにPromiseが返ってくるのは使いづらい。しかし、Node.jsの世界では、プロセスを止めて処理の結果を待つことが基本的にはできない。(bindingを書けばその限りではないけど。) top levelでawaitする方法があればどうにかなりそうだけど、今のJavaScriptの世界ではそれは許されていない。
Top-level `await` is a footgun · GitHub
というわけで以下のようになった。
execFileで子プロセスで出力処理をさせて、親プロセスではsleepのbindingライブラリで処理を停止(物理)して、出力結果を監視することで無理やり同期的にする荒技に辿り着いた
— じょう (@joe_re) 2017年5月6日
出力結果の監視 is ファイルが書き込まれたかどうか。node-sleepでプロセスを停止させつつ、一定周期でファイル出力がないか監視している。internalなネットワークの通信なので、大抵はほとんど待たずに結果を受け取れるはず。ReactNative側とwebsocketの接続ができていなかったりした場合には、一定時間後にタイムアウトになる。 無理やり感が漂っているので、もっといい方法をご存知の方はぜひ教えてください。
結構便利です
結構便利に使えている。こいつにstorageの状態のスナップショットの取得/復元をする機能とかあってもいいかなー。 興味のある方はぜひ使ってみてください。
CafePitchの区切り文字にheader要素を指定できるようにした
CafePitchはElectron製のMarkdownで書けるプレゼンテーションツールです。久々のアップデートです。
久々ということでAngularをrc versionから脱却してみたりとか、TypeScriptのバージョンを上げたりとか色々した。 Angularはbootstrap周りをごっそりと書き換えたけど、それ以外はあんまり変えなくても動いた。
しかしテスト周りは変わりすぎていて厳しかったので、ユニットテストは全部捨てた。もともとあまり書いていなかったし、僕の不勉強からかなりギリギリで動いている感じだったので、まぁいい機会だったかもしれない。
Spectronで書いているE2Eテストは無傷なので、そこで最低限は担保している。(はず)
今回のアップデートでは、以下のように設定用の吹き出しを出せるようにしていて、そこから区切り文字を設定できるようにした。
id:catatsuy さんが以下のつぶやきをしていて、お話を聞いてみると、見出し要素を区切り文字にしたいということだった。
markdownでいい感じのスライドを作りたいだけなのに、以外といいツールがない
— 人間 (@catatsuy) 2017年2月25日
理由を聞いてみると、自然な文章を書いて勝手にスライドができて欲しい(水平線は普通に文章を書く時にはあまり使わない)というのが理由で、なるほどーという感じだったのでやってみた。
@joe_re おお!普通の文章と同じように書いたら勝手にスライドになる、というのが自分の理想です。
— 人間 (@catatsuy) 2017年2月25日
対応したら是非教えてください😀
区切り文字を増やすにあたっては、markdownのparse結果に行番号が付いていると理想的だったんだけど、cafepitchの中で使っているmarkedでは位置情報までは取れなかったので、必要最小限の構文のみを、行単位でlexingする処理を実装した。
一応markedの実装を見て齟齬がないようにはしたつもりだけど、markdownのparseと違うロジックを使うのはバグりそうであんまり良くないよなー、という感じはあるので、本当は一緒にしたい。どなかたいい感じの実装があれば教えてください。
実際に試してみると、区切り文字を意識しなくて書けるのは結構いい感じ。 もし興味があれば是非お試しください。
FlowtypeでFluxアーキテクチャに型付けをするという発表をした
もう2週間ぐらい前になってしまいますが、ランサーズさん主催の勉強会で、Type-Safe Flux Using Flowtypeというタイトルで発表させてもらいました。
発表資料
ここ半年ぐらいReact + Flux + Flowtypeを使った環境で開発しているのですが、Fluxにおける型付けのパターンは自分の中では大分固まってきた感覚があります。
今年の弊社AdventCalendarでも、Qiitaの記事として書きました。
自分の中で固まってきたとはいえ、FlowtypeもTypeScriptもどんどん進化しているし、もっと良いパターンもありそうだなー、という感覚もあります。
ぜひ知見をお持ちの方はお話ししましょう。
主催のランサーズさん、登壇者の皆様、ご参加いただいた皆様、ありがとうございました。