実行環境はホームネットワーク内を想定しています。
PeerJS とは
PeerJSは、WebRTCを普通に使うよりも簡単に処理に組み込めるように開発されたJavaScriptライブラリです。
今回はNode.jsを使って簡単なシグナリングサーバーを自前で用意し、PeerJSを使ってそのサーバーにアクセスし、ブラウザ間のシグナリングをおこないます。
Ionicでピアを作成する
いつもの
$ ionic start p2p-text-chat blank
$ cd p2p-text-chat
PeerJSの型定義をインストール
$ npm install --save @types/peerjs
PeerJSの読み込み
「src/index.html」に下記を追加
<script src="https://cdnjs.cloudflare.com/ajax/libs/peerjs/0.3.14/peer.js"></script>
Talkクラスを定義する
今回は1回のメッセージをTalkインスタンスとして管理します。
class Talk {
constructor(
public srcId: string,
public destId: string,
public message: string
) {}
}
メッセージ送信フォームを作成
AngularでいうTemplate-driven Formsに従って作成します。
「接続先のPeerID」と「送信メッセージ」のどちらかでも空になっている場合、「Send」ボタンは非活性となります。
<!-- 自分のPeerID -->
<h3>Your PeerID is <span ion-text color="danger">{{ talk.srcId }}</span></h3>
<!-- 投稿フォーム -->
<form (ngSubmit)="onSend()" #talkForm="ngForm">
<!-- 接続先PeerID入力 -->
<ion-item>
<ion-label>Connect to</ion-label>
<ion-input name="destPeerId" type="number" required [(ngModel)]="talk.destId" #destPeerId="ngModel"></ion-input>
</ion-item>
<!-- 送信メッセージ入力 -->
<ion-item>
<ion-label>Message</ion-label>
<ion-input name="message" type="text" required [(ngModel)]="talk.message" #message="ngModel"></ion-input>
</ion-item>
<!-- 送信ボタン Required設定されているInputがある場合は非活性 -->
<ion-row>
<ion-col center text-center>
<button ion-button type="submit" [disabled]="talkForm.form.invalid">Send</button>
</ion-col>
</ion-row>
</form>
Talkインスタンスを初期化します。
また、ランダムなPeerIDを発行し、それを元にPeerインスタンスを作成します。
Peerインスタンスが無事に作成され、Listen状態となった場合、
生成したPeerIDをTalkインスタンスの設定します。
最後に他のPeerから接続を受けた場合の処理の流し先を設定します。
talk: Talk = new Talk('', '', '');
talkHistory: Talk[] = [];
peer: PeerJs.Peer;
ionViewDidLoad() {
this.start();
}
public start() {
const peerId = String(Math.floor(Math.random() * 900) + 100);
const options = {
host: location.hostname,
port: 9000
};
this.peer = new Peer(peerId, options);
this.peer.on('open', id => this.talk.srcId = id);
this.peer.on('connection', conn => this.receive(conn));
}
private receive(conn: PeerJs.DataConnection) {
conn.on('open', () => {
conn.on('data', data => this.showMessage(data));
});
}
showMessage(talk: Talk) {
this.talkHistory.push(talk);
}
入力したメッセージを送信する
Submitアクションを受けてonSend関数が実行されます。
onSend() {
const conn = this.peer.connect(this.talk.destId, { serialization: 'json' });
conn.on('open', () => {
conn.send(this.talk);
this.showMessage(this.talk);
});
}
Talk履歴を表示する
今回はion-cardを使いました。
<!-- トーク履歴表示 履歴が0の場合は表示しない -->
<ion-card *ngIf="talkHistory.length > 0">
<ion-card-content>
<ion-card-title>Talk</ion-card-title>
<ion-list>
<ion-item *ngFor="let talk of talkHistory;">
<h3>[{{talk.srcId}} -> {{talk.destId}}]</h3>
<p>{{ talk.message }}</p>
</ion-item>
</ion-list>
</ion-card-content>
</ion-card>
これでピアの準備ができました。
実行イメージは以下になります。
シグナリングサーバーを立てる
準備
Peerパッケージをインストール
$ npm install --save peer
コード
「peer.server.js」というファイルを作成し、以下を書きました。
var PeerServer = require('peer').PeerServer;
var server = new PeerServer({port: 9000});
以上。びっくりするぐらい簡単でした。
実行する
ターミナルを2つ立ち上げて、1つ目で
$ node peer.server.js
2つ目のターミナルで
$ ionic serve
こんな感じで動きます。
終わりに
基本中の基本ですがサクッと動きを確認することができました。
参考書籍にリンクをつけた本の内容の復習といった感じですね。
もっと流行らせるためには「Ionic使うとこんな感じでサクッとプロトタイプ作れますよー」って実例を増やしていった方がいいのかな・・・
結構やりこんだから流行って欲しいなー。
実コードはここ GitHubです。