LoginSignup
0
2

More than 5 years have passed since last update.

NodeJsでBitpointの価格を取得してレスポンスを返す

Last updated at Posted at 2018-03-03

環境

Unity2013.3.0p4
Windows10

概要

UnityからBitpointの価格情報のwebsocketのapiにアクセスしようとしたが、うまくいきませんでした。
仕方ないのでNodeJsからSockJs-Clientを使用して情報を取得、HttpServerを立て、HttpリクエストしてきたUnityに情報を返しています。

GoogleComputeEngineの設定、WinScpの設定

以下を参照して設定する
サーバのIPアドレス(外部IP)をメモしておく
GoogleComputeEngineのVMインスタンスにWinScpでログイン

プログラムのアップロード

WinScpを用いて後述の「bitpoint.js」と「serverBitpoint.sh」をアップロードし、パーミッションで実行権限を付与する
 ・WinScp上でファイルを選択し、プロパティから行う

NodeJsのインストール

SSHでサーバにログインし、「Putty」のコマンドラインを開く
「sudo yum install -y nodejs」と入力

opensslの更新

「sudo yum update openssl」と入力

モジュールのダウンロード

js内で参照しているモジュールをダウンロードする

・「npm init」と入力
 色々聞かれるがそのままリターン
 package.jsonができる
・「npm install -save XXX」と入力
 -saveでpackage.jsonにモジュール情報が保存される
 XXXはモジュール名
  Bitpoint.js内でrequireしているもの
  「node Bitpoint.js」と入力してエラーが出るものが足りないもの
   request
   sockjs-client
   date-utils
   ※他にもエラーと言われるものがあるかもしれない

プログラムの実行

「nohup ./serverBitpoint.sh &」と入力

プログラム

アクセストークンを取得しているがこれはダミー。
 USERNAMEとPASSWORDもダミー
 なぜか実行しないとwebsocketに通信できなかった(気のせいかもしれない)
bitpoint.js

const Crypto = require("crypto");
const Request = require('request');
const SockJS = require('sockjs-client');
const Http = require('http');
const Url = require('url');
const Qs = require('querystring');
require('date-utils');

const USERNAME = "hogehoge@hoge.com";
const PASSWORD = "fugafuga";
var _server;

Main();
function Main()
{
    GetAccessToken();
    CreateHttpServer();
}

function GetAccessToken()
{
    process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";

    var sha256 = Crypto.createHash('sha256');
    sha256.update(PASSWORD);
    var hash = sha256.digest('hex')

    Request.get(`https://public.bitpoint.co.jp/bpj-api/login?username=${USERNAME}&password=${hash}`, (error, response, body) =>
    {
        var accessToken = JSON.parse(body)['access_token'];
        console.log( 'access_token', accessToken );
    });
}

function CreateHttpServer()
{
    _server = Http.createServer();
    _server.on('request', function( req, res )
    {
        console.log("Method = ", req.method);
        console.log("STATUS: ", res.statusCode);
        console.log("Content-Type: ", res.getHeader("Content-Type") );

        var getParams = Url.parse( req.url, true );
        console.log( "Get:", getParams.query );

        if( req.method == 'POST' )
        {
            var body='';
            req.on( 'data', function( data )
            {
                body += data;
            });
            req.on( 'end', function()
            {
                var postParams = Qs.parse( body );
                console.log( "Post:", postParams );
                HttpResponse( req, res, getParams, postParams );
            });
        }
        else
            HttpResponse( req, res, getParams, null );
    });
    _server.listen(8080)
    console.log('Start Server');
}

function HttpResponse( req, res, getParams, postParams )
{
    var Responses =
    {
        "Default": function ()
        {
            res.writeHead(200, {'Content-Type': 'application/json'});
            var now = new Date().toFormat("YYYYMMDDHH24MISS");
            res.end( `{ "time":"${now}" }` );
        },
        "leverageTwoWay": function ()
        {
            var accessToken = ( getParams.query[ "access_token" ] ) ? getParams.query[ "access_token" ] : "";
            RequestLeverageTwoWay( accessToken, postParams, function( response )
            {
                res.writeHead(200, {'Content-Type': 'application/json'});
                res.end( response );
            });
        }
    }
    var uri = Url.parse(req.url).pathname;
    if (uri === "/")
    {
        Responses["Default"](); 
        return;
    }
    else if (uri === "/leverageTwoWay")
    {
        Responses["leverageTwoWay"]();
        return;
    }
}

function RequestLeverageTwoWay( accessToken, postParams, onResponse )
{
    var response = '{ "error":"" }';
    if( accessToken == "" )
    {
        response = '{ "error":"accessToken" }';
        console.log( response );
        onResponse( response );
        return;
    }
    if( postParams == null )
    {
        response = '{ "error":"postParams" }';
        console.log( response );
        onResponse( response );
        return;
    }

    var options = postParams;//{ 'server': '{"currencyCd1":"BTC","currencyCd2":"JPY"}' };
    const sock = new SockJS(`https://public.bitpoint.co.jp/bpj-api/leverageTwoWay?access_token=${accessToken}`, null, options );
    sock.onopen = function()
    {
        console.log( "Open:", sock.url );
    };

    sock.onmessage = function(e)
    {
        console.log( "Message:", e.data );

        var now = new Date().toFormat("YYYYMMDDHH24MISS");
        response = `{ "updatetime":"${now}", "data":${e.data} }`;
        sock.close();
    };

    sock.onclose = function()
    {
        console.log( "Close:", sock.url );
        onResponse( response );
    };
}

serverBitpoint.sh

#!/bin/bash
node bitpoint.js

 

クライアントプログラム

ApiLogin.Requestを呼び出し、AccessTokenを取得
ApiLeverageTwoWay.Requestを呼び出し、建てたサーバから価格情報を取得
返ってきたjsonは何らかのパーサーでクラスとかにする

・アクセストークンの取得
 「XXXX,YYYY」はBitpointのLogin時のメールアドレスとパスワード
Assets/ApiLogin.cs

    public class ApiLogin
    {
        public static Coroutine Request( ExchangeBitpoint exchange, UnityAction<string> onResponse )
        {
            var sha256 = SHA256.Create();
            var hash = sha256.ComputeHash( Encoding.ASCII.GetBytes( YYYY ) );
            var password = BitConverter.ToString( hash ).Replace("-", "").ToLower();

            var param = new Dictionary<string, string>();
            param[ "username" ] = XXXX;
            param[ "password" ] = password;

            var query = exchange.GenerateFormParameter( param );

            var api = "/login";
            return exchange.Request( RequestType.Get, api + '?' + query, null, onResponse );
        }

        public class Response
        {
            public string access_token { get; set; }
        }
    }

Assets/ApiLeverageTwoWay.cs

    public class ApiLeverageTwoWay
    {
        public static Coroutine Request( ExchangeBitpoint exchange, string accessToken, UnityAction<string> onResponse )
        {
            var query = "{ \"currencyCd1\":\"BTC\", \"currencyCd2\":\"JPY\" }";

            var api = "/leverageTwoWay";
            return exchange.Request( RequestType.RelayPost, api + "?access_token=" + accessToken, query, onResponse );
        }

        public class Response
        {
            public class Datum
            {
                public string currencyCd1 { get; set; }
                public string currencyCd2 { get; set; }
                public decimal seq { get; set; }
                public decimal buySellCls { get; set; }
                public string indicator { get; set; }
                public decimal price { get; set; }
                public decimal openPrice { get; set; }
                public decimal highPrice { get; set; }
                public decimal lowPrice { get; set; }
                public decimal preClosePrice { get; set; }
                public string priceDate { get; set; }
                public string openPriceDate { get; set; }
                public string highPriceDate { get; set; }
                public string lowPriceDate { get; set; }
                public string preClosePriceDate { get; set; }
                public decimal change { get; set; }
                public decimal changeRate { get; set; }
            }
            public string updatetime { get; set; }
            public string error { get; set; }
            public List<Datum> data { get; set; }
        }
    }

Assets/ExchangeBitpoint.cs
・「RequestType.RelayPost」でリクエストが呼ばれたときは自分が建てたサーバが呼ばれるようにしている
 XXXXにサーバのIpアドレスを入れる

using System;
using System.Collections;
using System.Linq;
using System.Net;
using System.Net.Security;
using System.Text;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Networking;

public enum RequestType
{
    Get,
    Post,
    Delete,
    RelayPost,  //Bitpoint
}

public class ExchangeBitpoint : MonoBehaviour
{
    private RemoteCertificateValidationCallback _remoteCertificateValidationCallback = new RemoteCertificateValidationCallback( ( sender, certificate, chain, sslPolicyErrors ) => { return true; } );

    public string GenerateFormParameter( Dictionary<string, string > dictForm )
    {
        string formParam = "";
        var count = dictForm.Count;
        var index = 0;
        foreach( var pair in dictForm )
        {
            formParam += pair.Key + "=" + pair.Value;
            index++;
            if( index < count )
                formParam += "&";
        }
        return formParam;
    }

    public Coroutine Request( RequestType type, string path, object query, UnityAction<string> onResponse, int timeout = 0 )
    {
        return StartCoroutine( OpRequest( type, path, query as string, onResponse, timeout ) );
    }

    protected IEnumerator OpRequest( RequestType type, string path, string query, UnityAction<string> onResponse, int timeout )
    {
        var url = "";
        if( type != RequestType.RelayPost )
            url = "https://public.bitpoint.co.jp/bpj-api" + path;
        else
            url = "http://XXXX:8080" + path;

        var prevCertCallback = ServicePointManager.ServerCertificateValidationCallback;
        ServicePointManager.ServerCertificateValidationCallback = _remoteCertificateValidationCallback;
        var httpRequest = (System.Net.HttpWebRequest)System.Net.WebRequest.Create( url );
        switch( type )
        {
            case RequestType.Get:
                httpRequest.Method = "GET";
                break;
            default:
                httpRequest.Method = "POST";
                httpRequest.ContentType = "application/json";
                byte[] bodyRaw = ( query != null ) ? Encoding.UTF8.GetBytes( query ) : null;
                httpRequest.ContentLength = bodyRaw.Length;
                var isRequest = false;
                httpRequest.BeginGetRequestStream( ( ar ) =>
                {
                    System.IO.Stream reqStream = httpRequest.EndGetRequestStream( ar );
                    //送信するデータを書き込む
                    reqStream.Write( bodyRaw, 0, bodyRaw.Length );
                    reqStream.Close();
                    isRequest = true;
                }, null );
                while( isRequest == false )
                    yield return null;
                break;
        }

        string text = null;
        bool isResponse = false;
        httpRequest.BeginGetResponse( ( ar ) =>
        {
            var response = (System.Net.HttpWebResponse)httpRequest.EndGetResponse( ar );
            var statusCode = (int)response.StatusCode;

            System.IO.Stream resStream = response.GetResponseStream();
            //受信して表示
            System.IO.StreamReader sr = new System.IO.StreamReader( resStream, System.Text.Encoding.UTF8 );
            text = sr.ReadToEnd();
            sr.Close();
        //  response.Close();
            isResponse = true;
        }, null );

        while( isResponse == false )
            yield return null;

        ServicePointManager.ServerCertificateValidationCallback = prevCertCallback;
        if( onResponse != null )
            onResponse( text );
        yield break;
    }
}

参考

DEVGRU

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2