https://d226lax1qjow5r.cloudfront.net/blog/blogposts/video-chat-javascript-opentok-nexmo-dr/Video-Chat-Application-with-OpenTok-and-Nexmo-In-App-Messaging.png

OpenTokとNexmo In-App Messagingでビデオチャットアプリケーションを構築する

最終更新日 May 11, 2021

所要時間:2 分

このブログポストでは、ビデオチャットやメッセージの送信を可能にするウェブアプリケーションを OpenTokNexmoアプリ内メッセージング.

完全なコードを見るには、以下をチェックしてほしい。 レポ.また 最近のウェビナーをご覧ください。

前提条件

Vonage API Account

To complete this tutorial, you will need a Vonage API account. If you don’t have one already, you can sign up today and start building with free credit. Once you have an account, you can find your API Key and API Secret at the top of the Vonage API Dashboard.

アプリの構造

ディレクトリを作成し、好きな名前を付ける:

mkdir video-messaging-app cd video-messaging-app

以下のコマンドを使って、ディレクトリ内にいくつかのファイルとサブフォルダを作成する:

mkdir public public/js views touch public/js/index.js views/index.ejs server.js config.js

プロジェクト構造はこのようになるはずだ:

video-messaging-app
├── package.json
├── package-lock.json
├── views
│   ├── index.ejs
├── public
│   ├── js
│       ├── index.js
├── config.js
├── server.js

依存関係

NPMプロジェクトを作成し、プロジェクトに必要な依存関係をすべてインストールする:

npm init -y // we use the -y flag to skip through the questions
npm install opentok @opentok/client nexmo nexmo-stitch express ejs

では、サーバー・コードを server.jsファイルに追加します。

const OpenTok = require('opentok');
const Nexmo = require('nexmo');
const express = require('express');

const app = express();
app.use(express.static(`${__dirname}/public`));

app.get('/', (req, res) => {
 res.json({
   opentokApiKey: null,
   opentokSessionId: null,
   opentokToken: null,
   nexmoConversationId: null,
   nexmoJWT: null,
 });
});

const PORT  = process.env.PORT || 3000;
app.listen(PORT, () => console.log(`Running server on PORT: ${PORT}`));

サーバーは ExpressJSを使用してサーバーを作成しましたが、OpenTok と Nexmo の両方の認証情報が空であることに注意してください。その前に、Nexmo CLI を使って Nexmo メッセージング・アプリケーションを作成してみましょう:

nexmo app:create video-messaging-app https://example.com/answer https://example.com/event --keyfile=private.key
nexmo conversation:create display_name="Nexmo In-App Messaging"
nexmo user:create name="jamie"
nexmo member:add YOUR_CONVERSATION_ID action=invite channel='{"type":"app"}' user_id=USER_ID // make sure to replace the conversation ID and the user ID

コマンドを使って app:createコマンドを使って、アプリケーションIDを取得する。 video-messaging-appのアプリケーションIDと秘密鍵がディレクトリに追加されます。アンサーとイベントのURLはサンプルURLに設定されていますが、後で変更することができます。コマンドを使って conversation:createコマンドを使って Nexmo In-App Messaging.これは後で会話に接続するために使用する会話IDになります。この user:createコマンドはまた、アプリケーションに関連付けられたユーザーを作成することもできます。このユーザー名は、JWT生成プロセスの一部として使用するので、注意してください。

TokBoxダッシュボードを使用してOpenTok APIプロジェクトを作成し、API KeyとSecretにアクセスできるようにします。

では config.jsファイルを開きましょう:

module.exports = {
 opentokApiKey: '',
 opentokApiSecret: '',
 nexmoApiKey: '',
 nexmoApiSecret: '',
 nexmoApplicationId: '',
 nexmoPrivateKey: '',
 nexmoConversationId: '',
};

適切な認証情報を config.jsファイル

設定変数のインポート

この server.jsファイルでは、設定変数をインポートして、これをインスタンス化するのに使おう。 OpenTokそして Nexmoクラスのインスタンス化に使えるようにする。

const {
 opentokApiKey,
 opentokApiSecret,
 nexmoApiKey,
 nexmoApiSecret,
 nexmoApplicationId,
 nexmoPrivateKey,
 nexmoConversationId,
 } = require('./config');


const opentok = new OpenTok(opentokApiKey, opentokApiSecret);
const nexmo = new Nexmo({
 apiKey: nexmoApiKey,
 apiSecret: nexmoApiSecret,
 applicationId: nexmoApplicationId,
 privateKey: nexmoPrivateKey,
});

では、有効なクレデンシャルを返せるように、GETリクエストパスを更新してみよう:

app.get('/', (req, res) => {
 opentok.createSession({
   mediaMode: 'routed'
 }, (error, session) => {
   if (error) {
     res.status(500).send('There was an error generating an OpenTok session');
   } else {
     const opentokSessionId = session.sessionId;
     const opentokToken = opentok.generateToken(opentokSessionId);
     const nexmoJWT = nexmo.generateJwt({
       exp: new Date().getTime() + 86400,
       acl: {
          "paths": {
            "/v1/users/**": {},
            "/v1/conversations/**": {},
            "/v1/sessions/**": {},
            "/v1/devices/**": {},
            "/v1/image/**": {},
            "/v3/media/**": {},
            "/v1/push/**": {},
            "/v1/knocking/**": {}
          }
       },
       sub: 'jamie' // this is the name we set when creating the user with the Nexmo CLI
     });
     res.json({
       opentokApiKey,
       opentokSessionId,
       opentokToken,
       nexmoConversationId,
       nexmoJWT,
     });
   }
 });
});

上記のコードを使って、誰かがブラウザから /パスを作成します:

  • OpenTokセッションID

  • 対応するセッションIDのOpenTokトークン

  • 適切なACLを持つNexmoアプリケーションのJWTトークン

クレデンシャルを取得するメカニズムができたので、アプリケーションのクライアント側で作業してみよう。

にある index.jsディレクトリにある jsディレクトリにあるファイルを開く。

const OT = require('@opentok/client');
const ConversationClient = require('nexmo-stitch');

const session = OT.initSession(opentokApiKey, opentokSessionId);
const publisher = OT.initPublisher('publisher');

session.on({
 streamCreated: (event) => {
   const subscriberClassName = `subscriber-${event.stream.streamId}`;
   const subscriber = document.createElement('div');
   subscriber.setAttribute('id', subscriberClassName);
   document.getElementById('subscribers').appendChild(subscriber);
   session.subscribe(event.stream, subscriberClassName);
  },
 streamDestroyed: (event) => {
   console.log(`Stream ${event.stream.name} ended because ${event.reason}.`);
  },
  sessionConnected: event => {
    session.publish(publisher);
  },
});

session.connect(opentokToken, (error) => {
 if (error) {
   console.log('error connecting to session');
 }
});

上のコードでは、OpenTokのセッションを初期化しています。 セッションを初期化しています。 initSessionオブジェクトの OTオブジェクトのメソッドを呼び出して OpenTok セッションを初期化します。次にパブリッシャーを作成し、以下のイベントリスナーを設定します: streamCreated, streamDestroyedそして sessionConnected.これらのイベントリスナーは、ストリームが作成された時にストリームを購読し、 ストリームが破棄された時にメッセージを出力し、接続が完了した時にセッションに 公開するために使用されます。そして、サーバーで生成したトークンを使ってセッションに接続します。

ビデオチャットのコードを追加したので、In-App Messagingを追加しましょう。

class ChatApp {
  constructor() {
   this.messageTextarea = document.getElementById('messageTextarea');
   this.messageFeed = document.getElementById('messageFeed');
   this.sendButton = document.getElementById('send');
   this.loginForm = document.getElementById('login');
  }
}

この ChatAppクラスは、In-App Messaging機能を追加するために使用されます。また、いくつかのDOM要素への参照も取得します。 index.ejsファイルで作成します。

先に進み、イベントやエラーをコンソールに記録するためのヘルパー・メソッドを ChatAppクラスにヘルパー・メソッドを追加しましょう:

errorLogger(error) {
   console.log(`There was an error ${error}`);
 }

 eventLogger(event) {
   console.log(`This event happened: ${event}`);
 }

次に ConversationClientをインスタンス化し nexmoJWTトークンで認証する必要があります:

 joinConversation(userToken) {
   new ConversationClient({
     debug: false
   })
   .login(userToken)
   .then(app => {
     console.log('*** Logged into app', app)
     return app.getConversation(nexmoConversationId)
   })
   .then(this.setupConversationEvents.bind(this))
   .catch(this.errorLogger)
 }

会話への参照ができたので、会話イベントを設定しよう:

 setupConversationEvents(conversation) {
   console.log('*** Conversation Retrieved', conversation)
   console.log('*** Conversation Member', conversation.me)

   conversation.on('text', (sender, message) => {
     console.log('*** Message received', sender, message)
     const date = new Date(Date.parse(message.timestamp))
     const text = `${sender.user.name} @ ${date}: <b>${message.body.text}</b><br>`
     this.messageFeed.innerHTML = text + this.messageFeed.innerHTML
   });
   this.showConversationHistory(conversation);
 }

のメソッドを呼び出すことで、会話履歴を取得することができます。 getEventsオブジェクトの conversationオブジェクトのメソッドを呼び出すことで会話履歴を取得できます。DOM上にチャット履歴を表示できるように、ヘルパーメソッドを作成しましょう。下を見ればわかるように、イベントを区別するために異なる typesを使ってイベントを区別しています:

  showConversationHistory(conversation) {
   conversation.getEvents().then((events) => {
     var eventsHistory = ""
      events.forEach((value, key) => {
       if (conversation.members.get(value.from)) {
         const date = new Date(Date.parse(value.timestamp))
         switch (value.type) {
           case 'text:seen':
             break;
           case 'text:delivered':
             break;
           case 'text':
             eventsHistory = `${conversation.members.get(value.from).user.name} @ ${date}: <b>${value.body.text}</b><br>` + eventsHistory
             break;
            case 'member:joined':
             eventsHistory = `${conversation.members.get(value.from).user.name} @ ${date}: <b>joined the conversation</b><br>` + eventsHistory
             break;
           case 'member:left':
             eventsHistory = `${conversation.members.get(value.from).user.name} @ ${date}: <b>left the conversation</b><br>` + eventsHistory
             break;
           case 'member:invited':
             eventsHistory = `${conversation.members.get(value.from).user.name} @ ${date}: <b>invited to the conversation</b><br>` + eventsHistory
             break;
            default:
             eventsHistory = `${conversation.members.get(value.from).user.name} @ ${date}: <b>unknown event</b><br>` + eventsHistory
         }
       }
     })
      this.messageFeed.innerHTML = eventsHistory + this.messageFeed.innerHTML
   })
 }

また、エンド・ユーザーがHTMLページ上でアクションを起こしたことを知るために、いくつかのユーザー・イベントをセットアップしなければならない:

 setupUserEvents() {
   this.sendButton.addEventListener('click', () => {
     this.conversation.sendText(this.messageTextarea.value).then(() => {
         this.eventLogger('text');
         this.messageTextarea.value = '';
     }).catch(this.errorLogger)
 })
 this.loginForm.addEventListener('submit', (event) => {
     event.preventDefault();
     document.getElementById('messages').style.display = 'block';
     document.getElementById('login').style.display = 'none';
     this.joinConversation(nexmoJWT);
  });
 }

コンストラクタで setupUserEvents()メソッドをコンストラクタで呼び出すようにしよう:

class ChatApp {
  constructor() {
   this.messageTextarea = document.getElementById('messageTextarea');
   this.messageFeed = document.getElementById('messageFeed');
   this.sendButton = document.getElementById('send');
   this.loginForm = document.getElementById('login');
   this.setupUserEvents();
  }
}

上のコードでやったことを復習しよう。というクラスを作りました。 ChatAppというクラスを作成しました。 ConversationClientを作成し nexmoJWTトークンを使って認証します。また、イベントリスナーを設定しました、 textを会話オブジェクトに設定します。会話から古いメッセージを取得するには getEventsメソッドを使います。DOMのイベントリスナーをいくつか使って、変更されたときに情報を表示します。

ChatApp クラスを作成したので、必要に応じて DOM 要素を使用できるように、onload イベントが発生した時に ChatApp クラスをインスタンス化してみましょう。

window.onload = () => {
 new ChatApp();
}

を完成させたら index.jsを完成させたら、次に index.ejsファイルに追加してみましょう:

<!DOCTYPE html>
<html>
  <head>
    <style>
      #login,
      #messages {
        width: 80% ; height: 300px;
      }

      #messages {
        display: none
      }

      #conversations {
        display: none
      }
    </style>
    <script type="text/javascript">
      const opentokApiKey = '<%= opentokApiKey %>';
      const opentokSessionId = '<%= opentokSessionId %>';
      const opentokToken = '<%= opentokToken %>';
      const nexmoConversationId = '<%= nexmoConversationId %>';
      const nexmoJWT = '<%= nexmoJWT %>';
    </script>
    <script src="/js/bundle.js"></script>
  </head>

  <body>
    <form id="login">
      <h1>Login</h1>
      <input type="text" name="username" value="">
      <input type="submit" value="Login" />
    </form>

    <section id="messages">
      <button id="leave">Leave Conversation</button>
      <h1>Messages</h1>

      <div id="messageFeed"></div>

      <textarea id="messageTextarea"></textarea>
      <br>
      <button id="send">Send</button>
    </section>

    <section id="conversations">
      <h1>Conversations</h1>
    </section>
  </body>
</html>

上記のコードは、誰かが /パスにアクセスしたときにサーバによってレンダリングされます。ご覧のように、OpenTok セッションと Nexmo Conversation クライアントで使用する認証情報を渡しています。

最後に、適切な変数を使って index.ejsビューを正しい変数でレンダリングするようにサーバーを修正しましょう:

res.render('index.ejs', {
    opentokApiKey,
    opentokSessionId,
    opentokToken,
    nexmoConversationId,
    nexmoJWT,
  });

これですべての準備が整ったので、次に startスクリプトを package.jsonファイルにスクリプトを追加しよう:

  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "browserify public/js/index.js -o public/js/bundle.js && node server.js"
  }

ターミナルで npm startを実行し、アプリケーションを実行する!

結論

このブログでは、OpenTokとNexmo In-App Messagingの重要なコンセプトを取り上げ、WebアプリケーションにライブビデオとIn-App Messagingを追加する機能を紹介します。完全なコードを見るには、以下を参照してください。 リポジトリ.

シェア:

https://a.storyblok.com/f/270183/384x384/63f654d765/manik.png
Manik Sachdevaヴォネージの卒業生

シニア・ソフトウェア・エンジニア。開発者と協力してAPIを作るのが好き。APIやSDKを構築していないときは、カンファレンスやミートアップで講演している。