WebRTCの基礎知識と、PeerJSを利用するための環境構築手順については前回の記事を参照してください。
CoffeeScript
PeerJSで実装する「遠隔作業支援システム」の中心的なロジックは、コールバックを駆使した複雑な実装が必要になります。また初期化処理など、スマートグラス側と監視端末側で重複する処理も出現するでしょう。そのため今回は、画面操作をハンドリングするロジック、PeerJSの操作とコールバックをハンドリングするロジック、シグナリングなどの共通ロジック、と責務を分割して見通し良く実装したいと思います。
ただし、JavaScriptはプロトタイプベースのオブジェクト指向言語のため、JavaやC#のようなクラスベースのオブジェクト指向言語が備えるクラス継承によるモデル化を行うのは面倒です(できないわけではありませんが)。またメソッド呼び出しとコールバック処理が混在するため、「コンテキストによってthisが指し示すオブジェクトが変わる」というJavaScriptの特性にも注意を払う必要があります。
そこで今回は、最新(version 1.7.1)のCoffeeScript 用いてロジックを実装することにします。CoffeeScriptはコンパイルによってJavaScriptに変換される小さな高級言語で、クラス宣言構文や便利な演算子の追加などJavaScriptの言語仕様を拡張し、変数の巻き上げやコンテキストによるthisの違いといったJavaScript特有のクセのある仕様を隠蔽してくれるため、今回の実装にはうってつけです。
なお、CoffeeScriptのインストール方法や詳細な文法、コンパイルオプションなどは本稿では解説いたしません。必要に応じて、CoffeeScriptの公式サイトや、CodeZineの連載記事『CoffeeScriptによるモダンなWebアプリケーション開発』などをご確認ください。
クライアント側のモジュール構成
今回実装する遠隔作業支援システムのクライアント側コードは、下記のモジュールから構成されています。各々のモジュールの全体的な構成を概観してみましょう。
クライアント側モジュールの完全なソースコードは、遠隔作業支援システムの公開リポジトリ(remote-monitor)を参照してください。
HTML
device.htmlやmonitor.htmlでは、読み込むべきJavaScriptと画面構成を定義します。
今回は下記のように直接JavaScriptをロードしましたが、RequireJSなどのモジュールローダーを利用しても良いでしょう。
<!-- device.html --> ... <head> ... <script src="http://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <script src="javascripts/lib/peer.js"></script> <script src="javascripts/remote-monitor.js"></script> <script src="javascripts/device.js"></script> <!-- monitor.htmlの場合はmonitor.js --> </head> ...
PeerJSを操作するモジュール
remote-monitor.coffeeでは、PeerJSの操作を行うクラスを実装します。
シグナリング処理などのスマートグラス側・監視端末側双方で共通で利用するロジックはBaseClassへ、スマートグラスだけで利用するロジックはBaseClassを継承したDeviceClassへ、監視端末だけで利用するロジックはBaseClassを継承したMonitorClassへ実装します。
# シグナリングサーバ定義 ※1 HOST = 'xxx.xxx.xxx.xxx' # シグナリングサーバのIPアドレスやホスト名 PORT = 9000 # シグナリングサーバが立ち上がっているポート PATH = '/remote-monitor' # シグナリングサーバ立ち上げ時に指定したAPI Prefix DEBUG = 3 # 経路探索用のSTUNサーバ/TURNサーバの定義 ※2 CONF = iceServers: [{ url: 'stun:stun.l.google.com:19302' }, { url: 'turn:homeo@turn.bistri.com:80', credential: 'homeo' }] # 公開オブジェクトのホルダー this.ns = {} ... class BaseClass # BaseClassの定義 ... class DeviceClass extends BaseClass # BaseClassを継承したDeviceClassの定義 ... class MonitorClass extends BaseClass # BaseClassを継承したMonitorClassの定義 ... this.ns.DeviceClass = DeviceClass # 公開オブジェクトホルダーにDeviceClassをセット this.ns.MonitorClass = MonitorClass # 公開オブジェクトホルダーにMonitorClassをセット
前回構築したシグナリングサーバのIPアドレス(やホスト名)と、起動スクリプトに指定したポートとAPI Prefixを適切に設定してください。
前回説明したように、スマートグラスと監視端末が同一ネットワークに所属していない場合経路確立のためにSTUNサーバやTURNサーバが必要です。上記のようにSTUNサーバやTURNサーバのURLを定義してください。
STUNサーバやTURNサーバを明示的に与えなかった場合、現在のPeerJSの実装ではGoogleのSTUNサーバが利用されます。
JavaScriptには名前空間を設定する機能がなく、関数内に閉じたローカル変数とプログラム全体で共有されるグローバル変数の2種類の変数スコープしかありません。そのため何も考えずに変数を宣言すると、グローバルな名前空間にその変数が設定されるため、他のスクリプトへ悪影響を及ぼす場合があります。そこでCoffeeScriptは通常、スクリプト全体を即時関数に閉じ込め、スクリプト内で生成したオブジェクトはグローバルな名前空間には公開しないJavaScriptを生成します(--bareオプションを付けてコンパイルすることでこの機能を抑制することも可能ですが)。
ただし今回は、DeviceClassとMonitorClassはdevice.coffeeやmonitor.coffeeから参照できなければなりません。
そこで上記のようにthis.ns = {} として公開オブジェクトを保持するためのホルダー ns をグローバル名前空間に設定し、他スクリプトから参照したいDeviceClassとMonitorClassをnsのプロパティとして持たせることでこの問題を解決します。