JavaScript
jQuery
Blockchain
NEM
nemDay 22

NEMのノードに確実に接続する方法

NEMのノードに照会しにいって、数秒待たされて。。。なんだよ、落ちてるのかよ?もしかして解体?
と思ったことありませんか?僕はあります。

NEM財団がノードを提供してくれてはいるのですが、これはNEMWalletデフォルト設定でもあり、
正直レスポンスが遅いです。表示に3秒かかると50%のユーザーが離れると言われているWebの世界ではこれは致命的です。

というわけで今回は、NEMのノードに素早く確実に接続する方法について考えてみました。
まずはノードリストを取得する方法。

getNodes()
function getNodes(){

    var d = $.Deferred();
    $.ajax({url: "https://s3-ap-northeast-1.amazonaws.com/xembook.net/data/v3/node.json" ,type: 'GET',timeout: 1000}).then(
        function(res){
            let nodes;
            nodes = res["http"];
            d.resolve(nodes);
        },
        function(res){
            d.resolve(["alice2.nem.ninja","alice3.nem.ninja","alice4.nem.ninja","alice5.nem.ninja","alice6.nem.ninja"]);
        }
    );
    return d.promise();
}

jQueryというライブラリを使用しています。もっとも普及しており初心者のかたでも分かりやすいライブラリです。
出来る人はもっと高級なライブラリにも置き換えて読んでいただけるかと思います。
Promiseを使っていないのはIEを使っている人がまだ多そうだからです。

ます、https://s3-ap-northeast-1.amazonaws.com/xembook.net/data/v3/node.json

にアクセスしています。このファイルが取れた場合は優良ノード一覧が nodesに格納されます。

おかげ様で優良ノード情報はver3を迎えました。ver2も引き続き動きます。
改良点は以下の通りです。

  • ハッシュでのトランザクション参照に対応しているノードも一覧表示
    • "apositlle" : {} 参照
  • 最新バージョン情報の表示
    • "latest_version": 参照。この値が思ったよりも高い場合は、新バージョンが存在します。
  • 最新バージョンとの互換性表示
    • "latest_compatible": 参照。この値がtrueの場合はバージョンアップしても互換性が保たれます。

優良と判定するための条件は以下の通りです。
http:1秒以内に3回のAPIコールに応答
https:3秒以内に3回のAPIコールに応答
apostille:8秒以内にblock hight 1 のデータを検索
これを1時間に1回の周期で行っています。

この優良ノード情報にアクセスできなかった場合、あるいは1秒経っても応答が無かった場合は、
やむなく財団のノード一覧をnodes変数に格納します。
latest_version や last_update が思った値でなかった場合も財団ノード情報を返すようにしましょう。

次に取得したnodes変数を元にアクセスします。

connectNode()
function connectNode(nodes,query2){

    var d = $.Deferred();
    let targetNode = nodes[Math.floor(Math.random() * nodes.length)] + ":7890";
    var res = $.ajax({url:  "http://" + targetNode + query2 ,type: 'GET',timeout: 1000}).then(

        function(res){
            d.resolve(res);
        }

    ).catch(
        function(res){
            return getNemAccountData();
        }
    );
    return d.promise();
}

先ほど取得した、優良ノード一覧nodesからランダムに1つ取り出し、非同期通信を行います。ここでタイムアウト値を設定しておきます。
接続に失敗した場合、あるいはタイムアウト値を超えた場合は呼び出し元関数(この場合はgetNemAccountData(),後述します)を再度コールしてやり直します。connectNodeをコールしてはいけません。jQueryの中で失敗判定フラグが立っているようで、次に接続に成功したとしても何も反応しなくなります。

では最後にどうやって使うかを見てみましょう。

getData()
var getNemAccountData = function(){
    var res = getNodes()
        .then(function(nodes){

            account_get_address_query = "/account/get?address=" + address;
            return connectNode(nodes,account_get_address_query,connectNode);
        }).then(function(result){
            console.log(result);
        });
    return res;
}

getNemAccountData-> getNodes() -> then() -> connectNode() -> then() -> console.log()
といった流れになります。
優良ノード情報を取得し(失敗すれば財団ノード情報)、接続試行(失敗すれば最初からやり直し)、最後に結果出力となります。

Deferredの説明などもう少し詳しいこともしたいのですが、それはまた後日に。
(このやり方がマスターできれば、ネットワークタイムを取得してからトランザクション発行、モザイクの小数点情報を取得してから単位計算などいったことも簡単にできるようになります。)

明日も引き続きよろしくお願いします。