Go製 Felica ライブラリ pasori に read without encryption コマンドと write without encryption コマンドを足した
Windows だけだが、拙作の Go製 Felica ライブラリ pasori に read without encryption
と write without encryption
コマンドを足した。
参考にした記事/サイト一覧
[PASMO] FeliCa から情報を吸い出してみる - FeliCaの仕様編 [Android][Kotlin] - Qiita
FeliCa Liteの片側認証 - hiro99ma site
使い方
基本的な使い方は cmd/dump
を見てもらえばいい。今のところ、FelicaWriteWithoutEncryption
に渡す書き込み値は最初の16バイトをユーザーブロック0に書くのみ。
MAC付読み込み/書き込みは今のところサポートしてない。
package main import ( "fmt" "github.com/bamchoh/pasori" ) func dump_buffer(buf []byte) string { str := "" for _, b := range buf { str += fmt.Sprintf("%02X", b) } return str } var ( VID uint16 = 0x054C // SONY PID uint16 = 0x06C3 // RC-S380 ) func main() { var err error fmt.Println("Please touch FeliCa") psr, err := pasori.InitPasori() if err != nil { panic(err) } defer psr.Release() err = psr.FelicaWriteWithoutEncryption([]byte{16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1}) if err != nil { panic(err) } b, err := psr.FelicaReadWithoutEncryption() if err != nil { panic(err) } fmt.Println(b) }
TODOアプリに react-beautiful-dnd を追加する
TODO アプリに ドラッグ&ドロップでタスクを動かせるようにした。
苦労した点1 Typescript と react-beautiful-dnd の相性
react-beautiful-dnd では公式には Typescript をサポートしていません。型定義にはflowtypeを使用しています。
ただ、@types/react-beautiful-dnd はあるようなので今回はそちらを使用しました。バージョンは10.0.3
しかし、この定義ファイルにも問題があるようで、そのままで使うと webpack のビルドでエラーが発生しました。
なので、node_modules/@types/react-beautiful-dnd/index.d.ts の中の React.ReactElement
の部分を React.ReactElement<any>
に書き換え
とりあえずビルドを通して使うことにしました。
苦労した点2 firebase realtime database との連携
上記の画像のように入れ替えを行うためには、移動させたい要素を移動させたい位置に挿入することで行うわけですが、realtime database には要素のインデックスは無く挿入用のAPIはありませんので、set()かupdate()で行う必要があります。set() は単体の値を設定するときの関数で、update() 関数は複数の値の書き込みに適しています。今回は update() 関数のほうが有用そうでしたので、そちらを使いました。一番初めに思いついた作戦は、移動させる要素をremove()で削除して、移動先以降の要素も削除して再度push() と set() で要素を追加する方法だったのですが、コストや処理の複雑さからやめました。二番目に思いついたのは移動元と移動先の間にある要素すべてに対して、値だけをスワップさせる方法です。
onDragEnd(payload:any) { const { dst, src, todos } = payload const database:any = this.getDatabase(); const startAt = dst.index const endAt = src.index+1 var todoAry:any = [] // 元の位置から移動先の位置までの部分配列を作成する // 自身より手前に挿入するか、後に挿入するかで作成方法を // 変えている。具体的には、手前に挿入する場合は要素の // 手前から部分配列の要素として挿入し、後ろに挿入する // 場合は後ろから挿入する。 // こうすることで、一番初めに移動させたい要素がくるので // 後の挿入処理が一元化できる。 if(dst.index < src.index) { for(var i = src.index;i >= dst.index;i--) { todoAry.push({...todos[i]}) } } else { for(var i = src.index;i <= dst.index;i++) { todoAry.push({...todos[i]}) } } // 挿入処理 // 初めの要素を取り出してから、次の要素を順次手前に移動させる // 移動させ終わったら、最後の要素に初めの要素を挿入する // id 要素だけは移動させてはいけないので、元の要素のidを使用する var tmp = {...todoAry[0]} for(var i:any = 1;i < todoAry.length; i++) { todoAry[i-1] = {...todoAry[i], id: todoAry[i-1].id} } todoAry[todoAry.length-1] = { ...tmp, id: todoAry[todoAry.length-1].id, } const todoRef = database.ref(`todos/${this.uid}`) // 更新がかかった要素を update() する var updates:any = {} todoAry.forEach((val:any) => { updates[`/${val.id}`] = val }) todoRef.update(updates) }
成果物
成果物は以下のリポジトリにある。
GitHub - bamchoh/react-study at b8d395774638edbf3132ea976410a90193496cba
react-beautiful-dnd を触ってみた
TODO アプリのTODOをドラッグ&ドロップで移動させたいなぁ。という欲求が高まってきたので、そういうライブラリがないか探してみたら、Atlassianが提供してる react-beautiful-dnd
というライブラリがあるようだったので使ってみた。
GitHub - atlassian/react-beautiful-dnd: Beautiful and accessible drag and drop for lists with React
使い方は動画になっていて、ステップバイステップで教えてくれるので良い。
Beautiful and Accessible Drag and Drop with react-beautiful-dnd from @alexandereardon on @eggheadio
今のところ、第5回まで見て、それの通りに作ってみてドラッグアンドドロップでリストが変えられるようになったので
最小構成のコード片が作れたかなと思って記事にしてみた。
動画の途中で コンポーネントの innerRef 属性に対して設定している箇所があったんだけど、うまく動かなくて色々調べてたら、styled-components v4
から innerRef が削除されて、React の ref 属性をそのまま使うようになったとかで、最新のコードでは innerRef 属性の代わりに ref 属性を使って設定する必要があるみたいだった。
詳しくは、ここらへん に書いてあるので読んでみるといいかも。
使い勝手としては、まぁ今のところは最小構成なのでもうちょっとインタラクティブに動いてほしいなぁと思うところはあれど、期待していたような動作をしてくれるので満足している。スマホからでも動かせるみたいだし、調整次第では使えるものになるかなぁと思っている。
あとは、Material-UI と併用できるのか?というところが気になるので、そのあたりを今後調べていきたい。
成果物はここ に上げた。
(2019/02/21 追記)
material-ui と styled-component を共存させることでドラッグアンドドロップが可能なリストを作成することができた。material-ui のみだと ref が参照できなくて react-beautiful-dnd がエラーを出してしまうようだった。
成果物はここ に上げた。
TODOアプリにfavicon を設定する
TODOアプリに favicon を設定する。ただ、Reactだとbody部分の要素しかいじれないので webpack で設定する。 色々試したけど、favicons-webpack-plugin が最終的にやりたいことにマッチしたので、それにした。 まず、プラグインをインストール。
$ npm i --save favicons-webpack-plugin
次に webpack.config.js
を編集
const FaviconsWebpackPlugin = require("favicons-webpack-plugin") module.exports = { plugins: [ new FaviconsWebpackPlugin('./src/favicon.png'), ] };
./src/favicon.png
をもとに Android / iPhone / Web 用の favicon が自動生成され index.html に自動でリンクされる。
ただ、このままだと、webpack-dev-server
ではちゃんと表示されなかったので、以下の設定を webpack.config.js
に追加した。
module.exports = { devServer: { contentBase: [path.resolve(__dirname, "public/")], }, }
以上!!
webpackでビルドしたjsファイル名にコンテンツハッシュを追加する
ローカルで開発をしていると jsファイルがブラウザでキャッシュされていて「あれ?動かないぞ?」という場面が何度かあった。Webブラウザ上だったら強制更新(Chrome だったら Shift + Ctrl + R) で解決できるんだけど、iPhoneとかのモバイルブラウザだとそういうわけにもいかないので対策が必要だった。
Cache Busting
というわけで、Cache Busting を導入する。Rails のアセットパイプラインにも導入されている方式でこれをwebpackにも導入できるはず。と予想していたが、やはりあった。
Cache Busting とは jsファイルのパス名に適当にクエリ文字列をつけ、別のファイル名として認識させることでキャッシュを別に行うという手法だと認識してる。クエリ文字列をビルド毎に別にしておけばキャッシュも別になるから、いつも最新のファイルが読み込まれるし、プロダクションだとクエリ文字さえ固定であれば同じキャッシュが呼ばれるので、みんな幸せ。
Webpack で Cache Busting
公式のドキュメント には 設定ファイル(webpack.config.js) に以下のように記述すれば解決すると記載されているし、実際その通りにしたらできた。
module.exports = { // 一部省略 output: { filename: '[name].[contenthash].js' } };
WebpackのCache Busting はクエリ文字列を付加するのではなくて、ファイル名をビルド毎に違う名前にすることでキャッシュされるのを回避してるようだ。この [contenthash]
の部分が実際にはハッシュ文字列に置換されてファイル名を構成する。
Todo アプリを firebase にデプロイしたがテストの書き方がわからなかった
ここ最近はブログの交信がさぼり気味だった。というのも、realtime database のテストの仕方がわからずに試行錯誤していたので、成果をあまりだせなかったというのが大きい。
fetch-mock からの脱却
ローカル環境のデータベースへアクセスしていたときは、データベースへのアクセスをREST API経由で行っていたので、クライアント側はfetch関数を使用していたが、realtime database は専用のクライアントAPIによってアクセスするためfetch関数は使えなくなった。それに伴って、fetch-mockを使用してテストを行っていた部分が壊れてしまったので、realtime database 用のモックが必要となった。調べてみると realtime database シミュレーターなるものがあったわけだが、これはデータベースのルールに関してテストするもので、かつ、まだベータ版とのことで使用は控えたほうがよさそうとの結論になった。
結局は jest のモックを使用して firebase.database を偽装することにした。
jest.fn()
jestはjavascript用のテストフレームワークでfecebookが主に開発を行っている模様。fetch-mock を使っているときは sinon というテストフレームワークを使用していたが、Reactを使う上では jest のほうが親和性が高いかな? と思ったので jest に切り替えた。
jestではモックを作成するのに jest.fn() を使う。内部で呼び出された関数に差し替えることで関数の呼び出しを偽装できる。実際には jest.fn().mockImplementation() によって関数を実装することで偽装する。
firebase.database() を偽装する
firebase.database() は sendToApiServer 内部で呼び出しを行っているので、現状のままでは簡単にモック関数と差し替えることはできない。なので、sendToApiServer 関数をやめて、DatabaseBridgeという名前のクラスを作成し、そいつに処理を移した。そして、getDatabase() という関数を作成し、const database = firebase.database()
となっている部分を const database = getDatabse()
にしたうえで、getDatabase() 関数の中で return firebase.database()
として外向けに公開することでテストでも差し替え可能な関数でありつつ、内部処理の影響を最小限にした。
モック関数をネストする
firebase.database() をモック化することには成功したが、そのあと database の関数を使用している処理もモック化しないと、その部分でコケてしまう。具体的には database.ref() や そのあとの ref.on() や ref.once() でコケる。それらを mockImplementation() を組み合わせて作成する。
const bridge = new DatabaseBridge() const mock = jest.spyOn(bridge, 'getDatabase'); // spyOn() は 第一引数で渡したインスタンスの中の第二引数のメソッドを監視する const mockDbRemove = jest.fn() // ref.remove() メソッドのモック const mockDbRef = jest.fn() // database.ref() メソッドのモック mockDbRef.mockImplementation(() => { // database.ref() メソッドを偽装する return { remove: mockDbRemove } } // ネストさせることで内部の関数もモック化する }) mock.mockImplementation(() => { // getDatabase() メソッドを偽装する return { ref: mockDbRef } // database.ref() のモック関数を埋め込み })
例えば、実装が以下のようになっている場合、getDatabase() で取得したデータベースオブジェクトはモックにさし変わっているので、その次の database.ref() はモックオブジェクトが持つメソッドが呼ばれることになる。同様にその次の ref.remove() もモックオブジェクトのメソッドが呼ばれる。
class DatabaseBridge { // 実際は firebase.database が使用されるが、テストでは mock変数に差し替えられる getDatabase() { return firebase.database(); } remove() { const database:any = getDatabaase() // ここでモック(mock)が返される const ref = database.ref(`...`); // ネストしたモック(mockDbRef)が実行される ref.remove() // mockDbRemove モックが実行される } }
モックオブジェクトのコール情報を確認する
偽装しただけではテストできないので、その時に渡された引数をチェックするテストを書く必要がある。
- expect(mock.mock.calls.length).toBe(???)
何回モックがコールされたかをチェックする。
- expect(mock.mock.calls[0][0]).toEqual(???)
コールされたときの引数の値が期待通りかをチェックする。
今のところ、この二つでまかなえているので、それ以外は今後覚えていく。
jest.fn().mockImplementationOnce()
モック関数のコールに対して一度だけ違う値を返したいみたいな場合は、mockImplementationOnce() で実装できる。
const mockDbOnce = jest .fn() .mockImplementationOnce(() => { return false }) .mockImplementationOnce(() => { return true })
このモックが呼ばれると、一回目はfalseを返すけど、二回目はtrueを返すようになる。
成果物
GitHub - bamchoh/react-study at 7c28892ea0cac3b23af46d18be7968fbdc86b2db
Firebase 入門(4) ~ Todo アプリをデプロイできるのか? (2)
この数日、Firebase Authentication と格闘してた。一応目処が立って Firebase realtime database を使ってのTodoアプリも完成したんだけど、FIrebase Authentication は 「Todo アプリをデプロイできるのか?」というとこの本質ではなかったなぁと思った。ただ、ちゃんとしたアプリを作りたい場合は必須の知識なので無駄ではなかったと信じたい。
typescript との連携
typescript だからと言って特に何もすることはなかった。
realtime database reference
database.ref(アドレス) で Reference オブジェクトが取得できる。このReference オブジェクトを使って値の取得だったり、値の追加だったりをする。
on() メソッド
on() メソッドは値をサブスクライブするのに使用する。逐一値をポーリングすることが不要になるので便利。
value
第一引数に"value" を指定すると、アドレスで指定した場所以下すべてのデータが返ってくる。一部を変更したとしても全部が返ってくる。
database.ref(`todos/${uid}`).on("value", function(snapshot) => { // todos/$uid 以下のデータがすべて送られてくる // { // "a": { // "id": "a", // "text": "todo 1", // "completed": false // }, // "b": { // "id": "b", // "text": "todo 2", // "completed": false // } // } // 値は snapshot!.val() で取れる console.log(snapshot!.val()) })
child_added
child_added
は項目の追加があった場合に追加部分だけが送られてくるので、データ量を少なくしたい場合に便利。
ref.on("child_added", function(snapshot) => { // todos/$uid/変更のあったデータ 以下のデータがすべて送られてくる // "value" の時とフォーマットが少し異なるので注意が必要 // { // "id": "a", // "text": "todo 1", // "completed": false // } // 値は snapshot!.val() で取れる })
child_removed
child_removed
は項目の削除があった場合に削除された項目部分だけが送られてくる
コードは child_added
と変わらないので省略
child_changed
child_changed
は項目に更新があった場合に更新があった箇所を含むブロックが送られてくる。例えば、以下のような構造があったとして
{ "a": { "id": "a", "text": "todo 1", "completed": false }, "b": { "id": "b", "text": "todo 2", "completed": false } }
"completed" を true にするように変更したとしたら、"b" 以下のデータブロックが送られてくる。child_added, child_removed 以外のなにがしかの交信がここで捕捉され通知されるといった感じだろうか。
ref.on("child_changed", function(snapshot) { // true になって送られてくる // { "id": "b", "text": "todo 2", "completed": true } console.log(snapshot!.val()) })
completed のトグル
先ほどの例のように "completed" を true にする。みたいな場合は以下のようにonceと組み合わせてsetを行う。
const database = firebase.database(); const ref = database.ref(`todos/${uid}/${id}/completed`) ref.once('value').then((snapshot) => { ref.set(!snapshot.val()) })
Action と Action Dispatcher
firebase realtime database が on() メソッドによってデータベースの交信をリアルタイムに通知してくれる関係で、それをトリガにアクションを作成し、dispatcher に投げられるようになった。ただ、Viewからのアクションをaction_dispatcherで捕捉しないとdatabaseへアクセスできなくなるので、View → Action Dispatcher の流れと Firebase → Dispatcher の2種類の流れができてしまう。これはもう仕方ないのかな?と割り切っているが、どうにかできるんだろうか。
View → Action Dispatcher の流れは今までと変わらないので省略。
Firebase → Dispatcher の流れは基本的に Firebase の on() メソッドで捕捉したデータをもとにアクションを作成して dispatcher に渡しているだけだ。Reducer が type によって action と state をマージするという流れは変わらない。
// Firebase Realtime Database 側 todosref.on('child_added', function(snapshot) { if(snapshot!.val() !== null) { dispatch({ type: 'todos/child_added', payload: snapshot!.val() }) } }, function(error:any) { console.log(error) })
// reducer 側 case 'todos/child_added': if(action.payload === undefined || action.payload === null) { return state } return [ ...state, action.payload ]
まとめ
一応、Firebase realtime database と連携させることで Todo アプリをデプロイすることができたが、色々コード的に汚い部分があるので、今後、思いついたタイミングで編集していこうと思う。
成果物
Merge pull request #19 from bamchoh/firebase · bamchoh/react-study@69cbf7b · GitHub