Documents

ログインしていません

ログインすると全てのDocumentsを閲覧可能です。

Stream for Subscriber

配信情報の受信には以下の3ステップが必要です。

受信したいチャンネルを選択します。
アクセストークン(JWT)を発行します。
Receive Messages
AXISサーバに接続し、メッセージを受信します。

本ページでは、AXISサーバへの接続と受信について解説します。

プロトコル

AXISはWebSocketSecure(WSS)で受信者へメッセージを送信します。

接続可能なAXISサーバの一覧は、Available Servers List APIを利用して取得できます。

Available Servers List API

https://axis.prioris.jp/api/server/list/

Available Servers List APIは、Headerに Authorization: Bearer <YOUR TOKEN> の形式でトークンを含めてアクセスすることでユーザ認証を行います。

認証に成功すると、以下のようなレスポンスを返します。

{
  "status": "return available servers list",
  "servers": [
    "wss://**********"
  ]
}

Subscriberは servers 配列から接続先を1件以上選択してください。

AXISサーバへ接続を開始するには、以下のようなheaderで接続先へリクエストを送ります。

GET /socket HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Host: **********
Sec-WebSocket-Key: d2ArvIX37KhsYpawqXshhA==
Sec-WebSocket-Version: 13
Authorization: Bearer <YOUR_TOKEN>

または、以下のようにQuery stringとしてtokenを含めて接続先へリクエストを送ります。

GET /socket?token=<YOUR_TOKEN> HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Host: **********
Sec-WebSocket-Key: oeP8DlnoAyVBnFrVm0i1Pg==
Sec-WebSocket-Version: 13

接続に成功すると、AXISサーバは以下ようなレスポンスを返します。

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: C3WI+/2ZyDA+bGZouLbFLY4Q/0I=

接続後、AXISサーバとの接続が正しく行われたことを通知するために、文字列 "hello" を送信します。これはJSON形式のメッセージフォーマットではありません。受信プログラムは、文字列 "hello" が受信できたことを確認してからJSONのデコードを開始してください。

また、ユーザごとに許可された最大同時接続数を超える接続を行なった場合、 error: Connection limit exceeded. max=2 といった文字列を送信します。

接続の維持

接続を維持するために定期的にデータを送信(Heartbeat)する必要があります。(60秒に1回程度の送信を推奨)

また、接続が切れた際に再接続を試みる、あるいは接続が切れたことを通知する仕組みを用意する必要があります。

メッセージ送信時のポイント

再接続

AXISサーバは、メンテナンスや証明書更新などのために接続を切断し、再起動することがあります。また、利用者とAXISサーバまでの間の回線状況が不安定な場合、接続が切断されることがあります。
利用者は、接続が切断された場合に自動的に再接続する仕組みをソフトウェアに組み込む必要があります。これには、再接続処理を、リトライ間隔を指数関数的に増大させながら実行するExponential Backoffアルゴリズムを適用するべきです。

接続が切断された場合の無制限の再接続試行は、AXISサーバや回線に対して不要な負荷を与えますのでお控えください。

サンプルコード

コード中の YOUR TOKEN を発行したアクセストークンで置き換えてください。

Python 2/3

以下のサンプルコードには接続断時に再接続を試みる仕組みが含まれていません。

requirements.txt
websocket-client==0.58.0
main.py
import websocket
import _thread
import time
import ssl

class SocketClient:
    access_token = None

    def __init__(self):
        self.access_token = "YOUR TOKEN"
        websocket.enableTrace(False)
        ws = websocket.WebSocketApp("wss://**********/socket", header=["Authorization: Bearer %s" % self.access_token], on_open=self.on_open, on_message=self.on_message, on_error=self.on_error, on_close=self.on_close)
        try:
            ws.run_forever(ping_interval=60)
        except KeyboardInterrupt:
            ws.close()

    def on_message(self, ws, message):
        print(message)

    def on_error(self, ws, error):
        print(error)

    def on_close(self, ws):
        print("### closed ###")

    def on_open(self, ws):
        print("### open ###")
        
if __name__ == "__main__":
    socket = SocketClient()

Node.js (v8〜)

npm installを実行した後、以下のように起動してください。

$ TOKEN=YOUR_TOKEN node app.js
package.json
{
  "name": "axis-subscriber-nodejs",
  "version": "1.0.0",
  "description": "AXIS Subscriber for Node.js",
  "main": "app.js",
  "dependencies": {
    "websocket": "^1.0.33"
  }
}
app.js
const WebSocketClient = require('websocket').client;
const client = new WebSocketClient();
const token = process.env.TOKEN;

const headers = {
    "Authorization": "Bearer " + token
};

var retrySec = 100;
var retryCount = 0;
const retryMax = 10;

client.on('connectFailed', function (error) {
    console.log('Connect Error: ' + error.toString());
    retryConnection();
});

client.on('connect', function (connection) {
    console.log('Subscriber Connected to AXIS');

    connection.on('error', function (error) {
        console.log("Connection Error: " + error.toString());
    });

    connection.on('close', function () {
        console.log('Connection Closed');
        retryConnection();
    });

    connection.on('message', function (message) {
        if (message.type === 'utf8') {
            if (message.utf8Data === 'hello') {
                retrySec = 100;
                retryCount = 0;
                console.log('---hello---');
            } else if (message.utf8Data === 'hb') {
                // echo back heartbeat string. nothing to do.
            } else {
                try {
                    const data = JSON.parse(message.utf8Data);
                    // do something...
                    console.log(data.channel); // <- channel name
                    console.log(data.message); // <- message body
                    console.log('-----');
                } catch (error) {
                    console.log(error)
                    console.log(message.utf8Data)
                }
            }
        }
    });

    function heartbeat() {
        if (connection.connected) {
            connection.sendUTF('hb');
            setTimeout(heartbeat, 30000);
        }
    }
    heartbeat();

});

function retryConnection() {
    retrySec = retrySec * 2;
    if (retryCount < retryMax) {
        retryCount++;
        console.log('Retry: ' + retryCount + " (delay " + retrySec + "ms)");
        setTimeout(socketConnect, retrySec);
    }
    else {
        process.exit();
    }
}

function socketConnect() {
    client.connect('wss://**********/socket', null, null, headers);
}

socketConnect();