Blockchain
NEM

拡張メソッドでNEMのリクエスト結果の確認を少し楽に

以前 Unityで仮想通貨NEMの入門 という記事を書きました。
その中で使用した小技についてです。

NEM公式APIマニュアルにもありますが、NEMで残高を確認したり送金したりということをすると大体結果はJSONとして返ってきます。
なお、生の値はJSONですが受け取る結果は使用するプラグイン等によります。現在使っている CSharp2nem というプラグインだと結果は Json.NET を介して整形され、 Class に入った状態で返ってきます。

例えば上記の記事だとXEM送金時にリクエストを飛ばしていますが、NEMではレスポンスでそのリクエストが上手くいったか、失敗したならその原因は何か、ということがわかるようになっています。

しかしこのレスポンス、数字でしか返ってきません。
つまり、

    // 送金リクエストの結果確認
    var response = accClient.EndTransaction (asyncResult);
    Debug.Log (response.Type);
    Debug.Log (response.Code);

    // 結果
    // 1
    // 1

こんな感じでしか値が返ってきません。

そのためいちいちその数字がどういう意味だったのかAPIマニュアルに確認しに行く必要があり、大変不便だったのでレスポンスに拡張メソッドを使用して手間を減らしていました。
拡張メソッドについては下記を確認してください。

拡張メソッド (C# プログラミング ガイド)

これを使えば、クラス等に後付けで機能を追加できます。例えば今回のように第三者が作成したプラグインに機能を追加したい場合や、裏技的な使い方だとインターフェイスに実装を加えられたりと色々できます。
そんな拡張メソッドを使うと先ほどのログはこんな感じになります。

    // 送金リクエストの結果確認
    var response = accClient.EndTransaction (asyncResult);
    Debug.Log (response.ToLog());

    // 結果
    // Type 1: The result is a validation result.
    // Code 1: Success result.

上記では英語になっていますが、文章は下記の日本語版に置き換えていただく等の対応をしていただくと良いかと思います。
https://www.pr1sm.com/crypto-coin/nem-nis-api-documentation-in-japanese/#nemRequestResult

最後に実際の拡張メソッドの実装です。ぼくはトランザクション作成時のものしか拡張メソッドを作成していませんが、根本的な実装は全て共通のため適宜良い感じに拡張していただいたら良いと思います。

using System.Text;
using CSharp2nem.ResponseObjects;

namespace CSharp2nemUtilities {

    public static class NemAnnounceResponseEx {

        public static string ToLog(this NemAnnounceResponse.Response response)
        {
            var sb = new StringBuilder ();

            // add Type and Code
            switch (response.Type) {
            case 1:
                sb.AppendLine ("Type 1: The result is a validation result.");
                appendValidationCodeString (sb, response.Code);
                break;
            case 2:
                sb.AppendLine ("Type 2: The result is a heart beat result.");
                appendHeartBeatCodeString (sb, response.Code);
                break;
            case 3:
                sb.AppendLine ("Type 3: The result indicates a status.");
                appendStatusCodeString (sb, response.Code);
                break;
            }

            sb.Append ("Message: ");
            sb.AppendLine (response.Message);

            sb.Append ("TransactionHash: ");
            sb.AppendLine (response.TransactionHash.Data);

            sb.Append ("InnerTransactionHash: ");
            sb.Append (response.InnerTransactionHash.Data);

            return sb.ToString ();
        }

        static void appendValidationCodeString(StringBuilder sb, int code)
        {
            switch (code) {
            case 0:
                sb.AppendLine ("Code 0: Neutral result.");
                break;
            case 1:
                sb.AppendLine ("Code 1: Success result.");
                break;
            case 2:
                sb.AppendLine ("Code 2: Unknown failure. The validation failed for unknown reasons.");
                break;
            case 3:
                sb.AppendLine ("Code 3: The entity that was validated has already past its deadline.");
                break;
            case 4:
                sb.AppendLine ("Code 4: The entity used a deadline which lies too far in the future.");
                break;
            case 5:
                sb.AppendLine ("Code 5: There was an account involved which had an insufficient balance to perform the operation.");
                break;
            case 6:
                sb.AppendLine ("Code 6: The message supplied with the transaction is too large.");
                break;
            case 7:
                sb.AppendLine ("Code 7: The hash of the entity which got validated is already in the database.");
                break;
            case 8:
                sb.AppendLine ("Code 8: The signature of the entity could not be validated.");
                break;
            case 9:
                sb.AppendLine ("Code 9: The entity used a timestamp that lies too far in the past.");
                break;
            case 10:
                sb.AppendLine ("Code 10: The entity used a timestamp that lies in the future which is not acceptable.");
                break;
            case 11:
                sb.AppendLine ("Code 11: The entity is unusable.");
                break;
            case 12:
                sb.AppendLine ("Code 12: The score of the remote block chain is inferior (although a superior score was promised).");
                break;
            case 13:
                sb.AppendLine ("Code 13: The remote block chain failed validation.");
                break;
            case 14:
                sb.AppendLine ("Code 14: There was a conflicting importance transfer detected.");
                break;
            case 15:
                sb.AppendLine ("Code 15: There were too many transaction in the supplied block.");
                break;
            case 16:
                sb.AppendLine ("Code 16: The block contains a transaction that was signed by the harvester.");
                break;
            case 17:
                sb.AppendLine ("Code 17: A previous importance transaction conflicts with a new transaction.");
                break;
            case 18:
                sb.AppendLine ("Code 18: An importance transfer activation was attempted while previous one is active.");
                break;
            case 19:
                sb.AppendLine ("Code 19: An importance transfer deactivation was attempted but is not active.");
                break;
            }
        }

        static void appendHeartBeatCodeString(StringBuilder sb, int code)
        {
            switch (code) {
            case 1:
                sb.AppendLine ("Code 1:Successful heart beat detected.");
                break;
            }
        }

        static void appendStatusCodeString(StringBuilder sb, int code)
        {
            switch (code) {
            case 0:
                sb.AppendLine ("Code 0:Unknown status.");
                break;
            case 1:
                sb.AppendLine ("Code 1:NIS is stopped.");
                break;
            case 2:
                sb.AppendLine ("Code 2:NIS is starting.");
                break;
            case 3:
                sb.AppendLine ("Code 3:NIS is running.");
                break;
            case 4:
                sb.AppendLine ("Code 4:NIS is booting the local node (implies NIS is running).");
                break;
            case 5:
                sb.AppendLine ("Code 5:The local node is booted (implies NIS is running).");
                break;
            case 6:
                sb.AppendLine ("Code 6:The local node is synchronized (implies NIS is running and the local node is booted).");
                break;
            case 7:
                sb.AppendLine ("Code 7:There is no remote node available (implies NIS is running and the local node is booted).");
                break;
            case 8:
                sb.AppendLine ("Code 8:NIS is currently loading the block chain.");
                break;
            }
        }
    }
}