NEM-sdkを使ってみる WebSocket編
少しバタバタしていたので間が空いてしまいましたが、引き続き以下のNEM-sdkを使ってみます。
今回はsdkを利用してWebSocketのAPIと接続してみます。
コネクターオブジェクトの作成
まずendpoint
とaddress
を渡してconnector
オブジェクトを作成します。
let endpoint = nem.model.objects.create("endpoint") (nem.model.nodes.defaultMainnet, nem.model.nodes.websocketPort); let address = "NDLHY5KMQTATAR7IBRBF32MAQWDK7333VNI2MD5W"; let connector = nem.com.websockets.connector.create(endpoint, address);
NISへの接続
次にconnector
オブジェクトのconnect
を呼んでNISへ接続し、返されたPromise
のコールバック関数でチャネルの購読処理や、リクエストを行います。
subscribe
チャネルの購読処理にはnem.com.websockets.subscribe
を利用します。
errors
文字通りなんだとは思いますが、今のところ何か流れてきたことがありません。
chain.height
現在のブロック高を返します。
chain.blocks
最新のブロックの情報と含まれるトランザクションの配列を返します。
account.data
アカウントの残高やパブリックキーなどの情報を返します。
account.transactions.recent
該当アドレスの最新25個の承認済トランザクション情報を返します。
account.transactions.unconfirmed
該当アドレスに関する未承認トランザクションを返します。
account.transactions.confirmed
未承認トランザクションが承認されたタイミングで、そのトランザクションを返します。
account.mosaics.definitions
該当アドレスが所有するモザイクの定義を返します。xemも含まれます。配列ではなくモザイクごとに別々にオブジェクトを返します。
account.mosaics.owned
該当アドレスのモザイク残高を返します。xemも含まれます。配列ではなくモザイクごとに別々にオブジェクトを返します。
account.namespaces.owned
該当アドレスがオーナーのnamespaceを返します。
requests
こちらからデータを要求する場合は、nem.com.websockets.requests
を利用します。
account.data
account.transactions.recent
account.mosaics.definitions
account.mosaics.owned
account.namespaces.owned
それぞれ該当のチャネルを購読していれば、そこにデータが流れてきます。
なお、account.transactions.recent
をリクエストすると、承認済トランザクションと共に未承認トランザクションも返ってきます。逆に、初回起動時にaccount.transactions.recent
をリクエストしていない場合、account.transactions.unconfirmed
を購読していても、すでにブロードキャスト済で未承認なトランザクションを把握出来ません。
コード
そのまま書くと関数名がいちいち長くて見づらいですが、コードは以下のようになります。
connector.connect().then(() => { console.log("Connected"); nem.com.websockets.subscribe.errors(connector, res => console.log("errors", res)); nem.com.websockets.subscribe.chain.blocks(connector, res => console.log("blocks", res)); nem.com.websockets.subscribe.chain.height(connector, res => console.log("height", res)); nem.com.websockets.subscribe.account.data(connector, res => console.log("data", res)); nem.com.websockets.subscribe.account.transactions.recent(connector, res => console.log("recent", res)); nem.com.websockets.subscribe.account.transactions.unconfirmed(connector, res => console.log("unconfirmed", res)); nem.com.websockets.subscribe.account.transactions.confirmed(connector, res => console.log("confirmed", res)); nem.com.websockets.subscribe.account.mosaics.definitions(connector, res => console.log("definitions", res)); nem.com.websockets.subscribe.account.mosaics.owned(connector, res => console.log("owned", res)); nem.com.websockets.subscribe.account.namespaces.owned(connector, res => console.log("namespaces", res)); nem.com.websockets.requests.account.data(connector); nem.com.websockets.requests.account.transactions.recent(connector); nem.com.websockets.requests.account.mosaics.definitions(connector); nem.com.websockets.requests.account.mosaics.owned(connector); nem.com.websockets.requests.account.namespaces.owned(connector); }, err => console.log("errorMessage", err));
実行時の流れ
まず接続に成功するとConnected
が出力され、リクエストしたdata
、recent
、definitions
、owned
、存在すればnamespaces
が返り、ブロックが進むごとにheight
とblocks
が返ります。
ちなみに接続に失敗すると10回繰り返してその後エラーが出力されます。
送金や着金があった場合、まずunconfirmed
が返ります。
この時点ではnem.com.websockets.requests.account.data
で最新データを要求してもまだ残高は変わっていないので、未承認トランザクションを含めるとどうなるかはこのunconfirmed
の結果を反映してあげる必要があるようです。
ブロックが進むとheight
とblocks
が返り、未承認のトランザクションが承認に変わるのでconfirmed
が返ります。
承認されると自分の残高が変わるので最新のdata
が返ります。ゼロになった場合は残高ゼロで値が返ります。
モザイク
xem以外のモザイクに動きがあった場合はdefinitions
とowned
が所有モザイクの数だけそれぞれ返りますが、ゼロになった場合はゼロが返るのではなく、該当モザイクのオブジェクトは何もかえってきません。
手持ちのモザイクの一つを送信してゼロになった場合、モザイクに動きがあったので残された他のモザイクについてdefinitions
とowned
は返りますが、該当のモザイクについては何も返らないという事になります。
返ってきたオブジェクトを次々と配列に入れていく作りにした場合、ゼロになったタイミングを把握出来ないのでいまいち使いにくいです。NanoWalletの実装もそうなっていて、送金後ゼロになった場合も、残高は更新されません。(少なくとも1.2.12ではそうでした)
何故配列で返す仕様にしなかったんだろう??
とりあえず、承認されたトランザクションを元に自力で計算するか、confirmed
のところで一旦配列をリセットし、definitions
とowned
を強制的にリクエストして再度配列を作り直すなど工夫が必要そうです。
これで残高、未承認トランザクションなど、リアルタイムでデータを更新可能なサービスが作れるようになりました。
今度こそチャーハンを作る準備は整った。かな?
※筆者のモチベーション向上のため、以下NEMアドレスへxemなりシットトークンなりの寄付を受け付けています。
NDY4RH-UZ3CZO-Z53O5H-NEXTEM-7UF5X3-MMDGH4-IMAD