NEM NanoWalletのServicesをnpmモジュール化する
前回に続いて、NEM NanoWalletの中身をnpmモジュール化していきます。
前回はUtilsをnpmモジュール化したので、今回はそのモジュールを利用した各種Servicesの移植に進みます。
Services
まずはServicesの中身を整理します。
- Alert
alert.service.js
エラーメッセージに関するサービス。
- Connector
connector.service.js
SockJSを利用してWebSocket APIに接続するサービス。
- DataBridge
dataBridge.service.js
NetworkRequestsやConnectorを利用してデータを取得、保持するサービス。
- NetworkRequests
networkRequests.service.js
各種APIへ接続するサービス。
- Transactions
transactions.service.js
各種トランザクションを作成するサービス。
- Wallet
wallet.service.js
カレントアドレスと接続ノードなどを設定するサービス。
- WalletBuilder
walletBuilder.service.js
アドレスを生成するサービス。
WebSocketでリアルタイムにデータを取得したいのであれば、Connector
とDataBridge
が必要になりますが、トランザクションを生成してブロードキャストするだけなら、NetworkRequests
とTransactions
があれば事足りるので、今回はこの二つのファイルを対象とします。
対象のファイル2ファイルは、上記のDataBridge
、Wallet
を参照しています。
DataBridge
については、NISとの時刻の同期を行っている部分を参照しているだけなので、今回は時刻同期無しでDataBridge
は無視します。
Wallet
については、今回は定数としてしか使わないので、定数を保持するだけのクラスとして実装します。本来はWallet
のインスタンスをコンストラクタで受ける形になるかと思います。
また、以下のconfig
フォルダにあるAppConstants
も参照しています。
AppConstantsはデフォルトのポート番号や、有効な言語の一覧などが入っている設定ファイルなので、スタティックな変数だけ持つクラスとして実装します。
Typescriptで実装する
せっかくなのでTypescriptで書き換えていきます。(と言っても片っ端からanyで型指定していくことに何の意味があるのかは知りませんがw)
まずは、TypeScriptのファイルと、生成されるJavaScriptのファイルをそれぞれ管理する必要があるので、少し環境を整えます。
src
がソース置き場、lib
が実体置き場ということにしてディレクトリを分けます。
npmには実体だけアップしたいので、.npmignore
に除外するsrc
フォルダを指定します。
.npmignore
src/
また、生成されたJavaScriptのファイルをgitで管理したくないので、.gitignore
に除外するlib
フォルダを指定します。
.gitignore
lib/
src
ディレクトリに移動してtsc
の--init
オプションでtsconfig.json
を生成し、outDir
で出力先を設定します。
tsconfig.json
{ "compilerOptions": { "module": "commonjs", "target": "es5", "noImplicitAny": false, "sourceMap": false, "outDir": "../lib" } }
最終的なディレクトリ構成は以下のようになります。
nem-services │ .gitignore │ .npmignore │ LICENSE │ package.json │ README.md │ ├─lib │ appConstants.js │ index.js │ networkRequests.js │ transactions.js │ wallet.js │ └─src appConstants.ts index.ts networkRequests.ts transactions.ts tsconfig.json wallet.ts
それぞれのサービスの実装
あとはそれぞれのファイルの、元のコードのままでは動かない部分について修正しつつ、狂ったように型指定していきます。
基本的にはそのままですが、AngularJSのhttp
部分をisomorphic-fetch
で書き換えました。
fetchした時に帰ってくるPromise
をObservable
にしていじくりまわしたのでrxjs
も必要になりました。
なぜここでRxJSかというと、それってモダンじゃね?ぐらいの感覚で良く分かってませんw
package.json
"dependencies": { "rxjs": "^5.1.0", "isomorphic-fetch": "^2.2.1", "nem-utils": "0.0.3" }
NetworkRequests
httpアクセス部分は以下のような感じです。
正直、Observable
の使い方、使いどころが正しいのか良く分かりませんが、動いたので正しいということにしておきます。
import * as fetch from "isomorphic-fetch"; import { Observable } from 'rxjs'; import 'rxjs/add/operator/map'; getHeight(host: string): Observable<number> { let url: string = "http://" + host + ":" + this.getPort() + "/chain/height"; return Observable.fromPromise(fetch(url)) .flatMap(response => response.json()) .map(json => json.height); }
Transactions
DataBridge
が担っていた部分は、以下のように書き換えました。
// let d = new Date(); // let timeStamp = Math.floor(this._DataBridge.networkTime) + Math.floor(d.getSeconds() / 10); let timeStamp: number = helpers.createNEMTimeStamp();
その他、jQueryを使っている部分をNativeなコードに直したり、型に関しては結構ゆるい作り(数値型っぽいところに突然エラーメッセージ配列を放り込む)になっていたので、その辺を微調整しました。
実行
以下のようにしてインポートして利用します。 プライベートキーは伏せてありますが、実際は正しいものを利用します。
import { Transactions } from "nem-services"; let common = { privateKey: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", password: "" } let dummyTransaction = { recipient: "NDLHY5KMQTATAR7IBRBF32MAQWDK7333VNI2MD5W", recipientPubKey: "099132a49ed0c15936a464cf6ef43120f01fa88835803593571882feea6161db", amount: 0, message: "sooooooooooooooooooooooooooooon", mosaics: null, fee: 12000000, innerFee: 0, due: 60, isMultisig: false, multisigAccount: "" } let tx = new Transactions(); let entity = tx.prepareTransfer(common, dummyTransaction, null); tx.serializeAndAnnounceTransaction(entity, common) .subscribe(s => console.log(s));
以下のレスポンスが返ってきました。
{ innerTransactionHash: Object, code: 1, type: 1, message: "SUCCESS", transactionHash: Object }
そして無事トランザクションが取り込まれました。
http://chain.nem.ninja/#/transfer/aa530b1189fa5401101df71232fa0cf0f883a5d25364e552ea95d986a2c215c4
※筆者のモチベーション向上のため、以下NEMアドレスへxemなりシットトークンなりの寄付を受け付けています。
NDY4RH-UZ3CZO-Z53O5H-NEXTEM-7UF5X3-MMDGH4-IMAD