Adobe XDのWebSocket機能をNode-RED経由で試すメモ

この記事は Adobe XD Plugins Advent Calendar 2018 の4日目の記事です。

昨日は ten_A_cclab さんの、 XDオートメーションに関する雑感 でした。

さて、私ですが、Adobe XDのWebSocket機能をNode-RED経由で試してみたいと思います。
Adobe XDプラグイン機能によるfetchで外部サーバーのNode-REDにやりとりするメモ – 1ft-seabass.jp.MEMO

今回やりたいこと

Adobe XDプラグイン機能によるfetchで外部サーバーのNode-REDにやりとりするメモで、外部に接続するための仕組みは整ったので、今回はWebSocketでどう連携していくか試していきたいと思います。

image

このように、Adobe XDでプラグイン機能から外部ネットワークアクセス(Network API)を試してみるメモで紹介したHTTPと同じようにWebSocketは外部サーバーとやり取りができます。

重要な点としては、一度接続されればチャットでのやり取りのように、向こう側(外部サーバー側)からデータを受信することも可能なところです。

Node-REDでWebSocketの受け手を作る

Node-REDではこのような仕組みを作ります。

image

Node-REDはさくらのクラウドで構築していて、スタートアップスクリプトでシンプルに作成できます。

作り方も記事がありますので、詳しく知りたい方は さくらのクラウドのスタートアップスクリプトでNode-REDをインストールするメモ を参考にしてみてください。

ただ、今回は、このフロー図を見つつ「あー、 /adobexd というWebSocketの窓口でAdobeXDがやりとりするんだな」くらいで把握いただいていれば問題ないです!

フローデータのJSONファイル置いておきます。

[{"id":"e6d3dba.6ff6128","type":"websocket in","z":"dcac63b0.a8ba1","name":"","server":"53b10c13.d87304","client":"","x":430,"y":280,"wires":[["ae1382fb.2b4d2"]]},{"id":"e82747d3.b7bd38","type":"websocket out","z":"dcac63b0.a8ba1","name":"","server":"53b10c13.d87304","client":"","x":740,"y":340,"wires":[]},{"id":"ae1382fb.2b4d2","type":"debug","z":"dcac63b0.a8ba1","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":730,"y":280,"wires":[]},{"id":"ef2fe0e2.ab759","type":"inject","z":"dcac63b0.a8ba1","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":440,"y":340,"wires":[["e82747d3.b7bd38"]]},{"id":"e83ffb68.b74588","type":"comment","z":"dcac63b0.a8ba1","name":"外部サーバー","info":"","x":430,"y":220,"wires":[]},{"id":"53b10c13.d87304","type":"websocket-listener","z":"","path":"/adobexd","wholemsg":"false"}]

AdobeXDのほうを作る

さて、プラグインの方を作ってみましょう。

Overview · Adobe XD Plugin Reference

から調べていきます。やっぱり充実してますね!

WebSocketまわりの様子

WebSocket · Adobe XD Plugin Reference

こちらを見てみます。

2018/12/03 時点で

image

しっかり準備されています。

manifest.json

manifestでは「WebSocket Open」「WebSocket Close」「WebSocket Send Select Text」を動かすためのuiEntryPointsを設定しています。

{
    "id": "NODE_RED_WEBSOCKET",
    "name": "Adobe XD WebSocket Node-RED plugin",
    "host": {
        "app": "XD",
        "minVersion": "13.0.0"
    },
    "version": "1.0.0",
    "uiEntryPoints": [
        {
            "type": "menu",
            "label": "WebSocket Send Select Text",
            "commandId": "wsSendCommand"
        }
        ,
        {
            "type": "menu",
            "label": "WebSocket Open",
            "commandId": "wsOpenCommand"
        }
        ,
        {
            "type": "menu",
            "label": "WebSocket Close",
            "commandId": "wsCloseCommand"
        }
    ]
}

main.js

WebSocket – Web API | MDN を参考にしつつ、以下のようにコードを書きました。

const { Text, Color } = require("scenegraph"); // XD拡張APIのクラスをインポート

// Adobe XDがNode-REDの該当URLにアクセスする
const wsurl = "ws://WEBSOCKET_SERVER_URL/adobexd";

let socket;

async function wsOpenFunction(selection) {
  // WebSocket.send でデータ取得
  // WebSocket 接続を作成する

  if( socket ){
    // 多重起動を防ぐ
    console.log("WebSocket opened already!!!");
  } else {
    socket = new WebSocket(wsurl);

    // WebSocket 接続をはじめる
    socket.addEventListener('open', function (event) {
        socket.send('Hello Server!');
        console.log("WebSocket started");
    });
  
    // メッセージを待ち受ける
    socket.addEventListener('message', function (event) {
      console.log('Message from server ', event.data);
    });
  
    // WebSocket 接続を終了を検知
    socket.addEventListener('close', function (event) {
      console.log("WebSocket closed");
      // WebSocketを消す
      socket = null;
      // 丁寧にremoveEventListenerすべき??
    });
  }

}

async function wsCloseFunction(selection) {
  console.log("WebSocket close...");
  socket.close();
}

async function wsHandlerFunction(selection) {
  console.log("wsHandlerFunction was called!"); // Developer Consoleに出力

  // 選択オブジェクトの取得
  console.log(selection.items.length + " items are selected");
  // selectList
  const selectList = [];
  // 選択したテキストを取得
  for(let i = 0 ; i < selection.items.length ; i++ ){
    const item = selection.items[i];
    // 全テキストデータを順番に突っ込んでおく
    selectList.push(item.text);
  }
  // WebSocket送信
  socket.send(selectList);
}

module.exports = {
  commands: {
    wsSendCommand: wsHandlerFunction,
    wsOpenCommand: wsOpenFunction,
    wsCloseCommand: wsCloseFunction,
  }
};

WEBSOCKET_SERVER_URLのところは、自分の設定したNode-REDのサーバーを設定しています。Node-REDの場合は1880というポートで待ち受けるのですがそのときはポートも忘れないようにしましょう。ここはWebSocketを立ててるサーバーによって変わってくるでしょう。設定合わせてお使いください。

ということで、このプラグインが無事インストールされていると、

image

このように、「WebSocket Open」「WebSocket Close」「WebSocket Send Select Text」機能が作られます。

動かしてみる

プラグインを動かしてみましょう。

WebSocket Open

まず、WebSocketを接続してみましょう。

image

WebSocket Openをクリックします。

image

Node-REDでできた先ほどのサーバーに connected 1 となって無事つながります。

image

そして、Adobe XDからNode-REDへメッセージが飛んでいます!

また、Node-REDから injectノードよりタイムスタンプのデータを送るのもAdobe XDが受け止めています!

image

さすがWebSocketレスポンス早い!

WebSocket Send Select

では選択したテキストを送ってみましょう。

image

このようにテキストを選択して「WebSocket Send Select 」をクリックします。

image

すると、まず送ったよとメッセージがDeveloper Consoleに出てきます。

image

Node-REDで受信されて、選択されたテキストがカンマ区切りで送られています。これは、リストを配列で入れたので展開してくれたのでしょう。JSON.stringfyを駆使すればJSON状に送ることも可能でしょう。

WebSocket Close

最後にクローズです。

image

WebSocket Closeをクリックします。

image

Developer consoleでも、WebSocket終了イベントが反応して、ちゃんとWebSocketがクローズされます。

image

Node-REDでも切断されたとステータスが変わりました。ちゃんと動いてる!

ということでAdobe XDでWebSocketが動いた!

Adobe XDでWebSocketで動きましたね!

雑感を書いておきます。

  • Adobe XDでのWebSocketはイベントを受け取るaddEventListenerもあり素直に動く模様
    • ドキュメントにsendしか書かれてないので、受信ダメなのかな?と思ったけど、なんら問題なかった
  • .xdファイルを立ち上げるたびにウィンドウ単位で初期処理が走る模様
    • WebSocketのインスタンスを追えるようにしておかないと管理しづらくなりそう
    • ウィンドウごとの横断的な変数管理をできるのだろうか?
  • WebSocketはHTTPをくらべてレスポンスが早い
    • ちゃんと起動している間は終了しない限り生き続ける
  • ドキュメントには明記されてないが WebSocket.readyState みたいなプロパティも使える模様

といったところを感じることができました。

WebSocketができると、AdobeXDからデータを送るだけでなく、リアルタイムに相互にやり取りができるようになるので、操作と連携できたり色々できそうですね!

引き続き調べていきます!

それでは、よき Node-RED & Adobe XD & WebSocket Lifeを!