JavaScript
Socket.io
nodejs
websocket

WebSocketを利用してサーバからクライアントにイベントを通知するライブラリを作ってみた

とある案件で
・サーバからクライアントに対してイベントを通知して処理したい
・でも既存のシステムはそのまま使いたい
といった要望があったので、そのときの対応メモ

以前FCMを利用してServiceWorkerでやりとりしてもと思ったが、
対応ブラウザやPush配信の仕組みなど少し手間がかかりそうだったので、
Node.js/Socket.ioの組み合わせで通知の仕組みだけを構築してみることに...

FCMについての記事は下記をご参考ください。
Firebase Cloud Messaging(FCM)を利用したWebPush通知の実装について

システム概要

イメージとしては添付画像のような形で、WebSocketにて通信する部分は別サーバで実施。
単純に通知のやりとりを行うハブとして独立させ、
クライアント側はイベントを受信したときに既存のシステムに対してイベントを通知して処理を行う。

WebSocketNotification概要図.png

こうすることで、既存のシステムを大きく改修しなくても
サーバからクライアントに対して任意のタイミングで任意の処理が出来るようになり、
イベントの購読という形でシンプルに実装可能なのかなと思い着手。

主にWebSocketで接続しているユーザの管理を既存のアプリケーションシステムで管理しているユーザで通知処理が行えるように(ユーザIDやグループの管理など)ライブラリ内で実装しています。

実際に構築したものは下記を参考に...
作りの部分とか改善可能なところが多いですが、一旦動くようにと...
https://github.com/brightvie/webSocketNotification

実装例

サーバ

ExpressとSocket.ioのNode.jsサーバは用意する必要がありますが、
簡単に上記を実現するために組み込むことが出来ます。

server.js
// ユーザ管理の仕組みの初期化も含めてここで実施
var WebSocketNotification = require('websocket-notification');
var webSocketNotification = new WebSocketNotification();

io.on('connection', function(socket){

  // WebSocket Notification Libraryで標準で用意されているメソッドを付与する
  // - ユーザ管理: login, disconnect イベントの設定
  // - 通知: POST /notification APIの実装
  webSocketNotification.setMethod(io, socket, app);
});

クライアント

Webのクライアント側はBowerでライブラリを読み込み後
下記のように初期化するだけで機能実装は可能

index.html
<script src="/components/socket.io-client/dist/socket.io.js"></script>
 <script src="/components/webSocketNotification/src/client/client.js "></script>
 <script>
   var obj = {
     systemName: '所属するシステムID' // 任意、指定がない場合はサーバ側でdefalutsが指定される
     userId: 'ユーザのIDを指定',     // 任意、指定がない場合はサーバ側でsocket.idが指定される
     groups: ['所属するグループIDなどを指定'] // 任意、指定がない場合は空配列となる
   };

   // WebSocket Clientの初期化
   var client = new WebSocketNotificationClient();
   // 任意のパラメータをセットする
   client.setOptions(obj);
   // WebSocketのコネクションを貼る
   var webSocket = client.getInstance(io);

   // getInstanceで返ってくる値は、socket.io-clientのインスタンスであるため、
   // 通常のsocket.on('イベント名', function(){}); といった書き方が可能である

   // サーバから通知を受け取ったときの処理を定義する。(デフォルトは、console.logでレスポンスが表示されるのみ)
   webSocket.on('notification', function(res) {
     // TODO: ここに処理を記載
     // - Angularなどのフレームワークに対してイベントを発火し、任意の処理を行うのもよし
     // - ここにべた書きで実施したい処理を行うのもよし
   });
 </script>

任意のイベントの発火

ここまで来るとあとは、既存のアプリケーションシステムからWebSocket経由で通知を送る部分です。
サーバ内部でのHTTPリクエストをイメージしており下記のようなリクエストを投げることで通知が行く仕組みです。

curl -X POST http://localhost:3000/notification -d '{"sentType": "user", "target": ["10001"], "message": {"statusCode": 200, "action": "alert"}}'

まとめ

とりあえずWebSocket経由で既存システムを活かしたまま簡単にサーバからクライアントにイベントを送り、処理を行うことは出来たのですが、nodejsのプロセスが再起動するとユーザ情報が消えたり、インフラ側の整備がまだまだだったり、本番運用が想定された作りではないので今後改修をいれつつ、まずは小さい機能から組み込んで使い勝手を見ていければと思います。