LoginSignup
13
8

More than 5 years have passed since last update.

【Ionic】PeerJSを使ってP2Pチャットアプリを作る

Posted at

実行環境はホームネットワーク内を想定しています。

PeerJS とは

PeerJSは、WebRTCを普通に使うよりも簡単に処理に組み込めるように開発されたJavaScriptライブラリです。

PeerJS - GitHub

今回は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>

これでピアの準備ができました。
実行イメージは以下になります。

スクリーンショット 2018-05-04 1.02.05.png

シグナリングサーバーを立てる

準備

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

こんな感じで動きます。

スクリーンショット 2018-05-04 1.11.35.png

終わりに

基本中の基本ですがサクッと動きを確認することができました。
参考書籍にリンクをつけた本の内容の復習といった感じですね。

もっと流行らせるためには「Ionic使うとこんな感じでサクッとプロトタイプ作れますよー」って実例を増やしていった方がいいのかな・・・

結構やりこんだから流行って欲しいなー。

実コードはここ GitHubです。

参考書籍

HTML5/WebSocket/WebRTCによる
TypeScriptネットワークプログラミング

13
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
8