
Partager:
Je suis développeur JavaScript et éducateur de développeurs chez Vonage. Au fil des ans, j'ai été très intéressé par les modèles, Node.js, les applications Web progressives et les stratégies offline-first, mais ce que j'ai toujours aimé, c'est une API utile et bien documentée. Mon objectif est de faire en sorte que votre expérience de l'utilisation de nos API soit la meilleure possible.
Construire une hotline JavaScript avec OpenTok et Node.js
Temps de lecture : 12 minutes
Il fut un temps où les gens qui avaient des questions sur JavaScript se rendaient sur IRC (Internet Relay Chat) pour trouver quelqu'un qui puisse leur répondre. L'IRC est une technologie très ancienne dans le domaine de l'internet. De nos jours, de nombreux développeurs JavaScript n'ont peut-être même pas de client IRC, ou n'en ont jamais utilisé. La plupart d'entre eux, en revanche, sont très familiers du chat vidéo.
OpenTok permet déjà de démarrer rapidement avec un simple Video chat entre deux participants. En ajoutant un peu de logique de file d'attente, vous pouvez disposer en un rien de temps d'une ligne d'assistance pour les questions relatives à JavaScript, ou à tout autre sujet.
Pour rendre votre hotline encore plus conviviale, vous pouvez construire le projet sur Glitch. Cela signifie que vous aurez moins d'installation à faire. Cela rend également votre hotline plus en fournissant le projet complet pour que d'autres puissent le remixer pour leurs propres hotlines.
Débuter sur Glitch
Si vous souhaitez passer à un projet fonctionnel, vous pouvez remixer le projet de hotline JavaScript sur Glitch. projet JavaScript hotline sur Glitch tout de suite. Sinon, en quelques étapes seulement, vous pouvez coder votre propre hotline à partir de zéro. Pour commencer, créez un nouveau projet sur Glitch, en choisissant le modèle hello-express modèle.
Pour permettre le chat vidéo avec OpenTok, opentok est en fait le seul package supplémentaire dont vous avez besoin. L'ajout de l'option permettant de recevoir un texte lorsque quelqu'un a besoin d'une réponse à une question permettra à la ligne d'assistance de mieux faire face aux variations du volume d'utilisateurs. Pour cela, vous pouvez également installer body-parser pour recevoir les formulaires et nexmo pour envoyer vos textes :
pnpm install opentok body-parser nexmo -sVous pouvez réutiliser l'exemple server.js, index.html, et client.js déjà présents dans votre projet Glitch. Cela signifie que votre installation est pratiquement terminée.
Fournir des variables d'environnement
Votre fichier .env ressemblera à ceci :
Pour fournir des valeurs réelles pour ces variables, vous aurez besoin de comptes de développeur à la fois sur OpenTok et Nexmo. Vous aurez également besoin d'un projet OpenTok et d'un numéro virtuel Nexmo.
Dans le tableau de bord de votre tableau de bord de votre Account OpenTokcréez un nouveau projet pour votre hotline avec le type de projet "OpenTok API". Après lui avoir donné un nom et sélectionné un codec Video (VP8 devrait convenir), vous verrez sa clé API et son secret. Vous pouvez les coller dans OPENTOK_API_KEY et OPENTOK_SECRETrespectivement.
Vos identifiants Nexmo, que vous pouvez coller dans NEXMO_API_KEY et NEXMO_API_SECRETVous devriez pouvoir les voir sur la page "Getting Started" de votre tableau de bord Nexmo. Vous pouvez utiliser n'importe quel numéro de téléphone de "[Vos Numbers](${CUSTOMER_DASHBOARD_URL}/your-numbers" sans configuration pour FROM_PHONEVous pouvez utiliser n'importe quel numéro de téléphone de "[Vos Numbers](${CUSTOM_DASHBOARD_URL}/your-numbers}" sans configuration pour Nexmo, puisque vous enverrez des SMS à partir de ce numéro, mais ne recevrez ni SMS ni appels.
Configuration du serveur
Votre serveur comprend déjà quelques éléments d'initialisation, une route de vue pour la racine de l'application et un écouteur qui démarre le serveur. Vous pouvez modifier légèrement la section d'initialisation afin d'utiliser également l'élément body-parser middleware :
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
app.use(express.static('public'));
app.use(bodyParser.json());Sous ce bloc, vous pouvez ajouter de nouveaux objets OpenTok et Nexmo initialisés avec les valeurs de .envet deux tableaux vides. waiting est destiné aux identifiants de session des chats qui attendent qu'un assistant réponde à une question, et helpers est le numéro de téléphone des personnes qui ont offert leur aide pendant les temps d'arrêt où personne n'avait de question à poser.
const OpenTok = require('opentok');
const opentok = new OpenTok(process.env.OPENTOK_API_KEY, process.env.OPENTOK_SECRET);
const Nexmo = require('nexmo');
const nexmo = new Nexmo({
apiKey: process.env.NEXMO_API_KEY,
apiSecret: process.env.NEXMO_API_SECRET
});
var waiting = [];
var helpers = [];Dans le reste du fichier, entre la route par défaut et le listener, vous pouvez déclarer les autres routes. En dessous, vous aurez besoin d'une fonction pour envoyer un message à la personne qui s'est proposée pour répondre aux questions :
app.get('/', function(request, response) {
response.sendFile(__dirname + '/views/index.html');
});
app.get('/ask', function(request, response) {});
app.get('/answer', function(request, response) {});
app.get('/answer/:sessionId', function(request, response) {});
app.post('/text', function(request, response) {});
function textHelper(sessionId) {}
const listener = app.listen(process.env.PORT, function() {
console.log('Your app is listening on port ' + listener.address().port);
}); Ajouter des participants aux questions-réponses
La fonction la plus élémentaire de l'application de hotline est de mettre en relation une personne posant une question avec une personne proposant d'y répondre. La manière la plus directe d'y parvenir est de créer une session de chat vidéo lorsque quelqu'un déclare vouloir poser une question. Vous pouvez ensuite ajouter la prochaine personne disponible souhaitant répondre en tant que deuxième participant. Vous pourriez créer un moyen plus robuste de gérer ces sessions actives à l'aide d'un magasin de données, mais à des fins de test, un tableau devrait suffire.
Lorsque quelqu'un pose une question, vous pouvez créer une nouvelle session OpenTok et stocker son identifiant dans le tableau waiting tableau. Vous pouvez ensuite répondre avec le nouvel ID, la clé API OpenTok de l'application et un jeton identifiant ce client spécifique :
app.get('/ask', function(request, response) {
opentok.createSession(function(err, session) {
let sessionId = session.sessionId;
waiting.push(sessionId);
response.send({
apiKey: process.env.OPENTOK_API_KEY,
sessionId: sessionId,
token: opentok.generateToken(sessionId)
});
if (helpers.length) {
textHelper(sessionId);
}
});
});Vous pouvez voir que le
/askvérifie, dans une dernière étape, la longueur duhelpers. S'il y trouve des éléments, il appelle la fonctiontextHelperfonction. Nous aborderonstextHelperséparément ci-dessous, mais si vous voulez simplifier votre hotline en ne connectant que les personnes qui utilisent actuellement votre application, vous pouvez supprimer toute cette condition.
Désormais, lorsque quelqu'un propose de répondre à une question, vous pouvez envoyer un objet de réponse similaire contenant les valeurs de la première session de la file d'attente waiting file d'attente. Si la file est vide, vous pouvez envoyer une réponse indiquant au client que personne ne demande de l'aide pour le moment :
app.get('/answer', function(request, response) {
if (waiting.length) {
let sessionId = waiting.shift();
response.send({
apiKey: process.env.OPENTOK_API_KEY,
sessionId: sessionId,
token: opentok.generateToken(sessionId)
});
} else {
response.send({
wait: true
});
}
}); Envoyer un SMS à un assistant lorsque quelqu'un pose une question
Cela complique un peu notre flux de travail actuel, mais le fait de permettre aux aidants potentiels de fournir leur numéro de téléphone et de recevoir un message lorsqu'une nouvelle session de questions est prête permet à la ligne d'assistance de mieux faire face aux périodes creuses.
Sauvegarder le numéro de téléphone d'une personne ne nécessite que quelques lignes de code. Le point de terminaison /text reçoit le numéro de téléphone dans le corps de sa requête et peut ensuite l'ajouter à une file d'attente. helpers file d'attente. Il renvoie ensuite un état "OK" :
app.post('/text', function(request, response) {
let phone = request.body.phone;
helpers.push(phone);
response.sendStatus(200);
});Nous pouvons maintenant utiliser le numéro de téléphone enregistré de l'assistant dans la fonction textHelper qui est appelée par la fonction /ask route. La fonction récupère le premier numéro de téléphone à partir de helpers et lui envoie un lien vers une session de chat vidéo spécifique :
function textHelper(sessionId) {
let phone = helpers.shift();
nexmo.message.sendSms(
process.env.FROM_PHONE,
phone,
'JavaScript question for you! Caller is waiting at: https://' + process.env.PROJECT_DOMAIN + '.glitch.me/?id=' + sessionId
);
}Si quelqu'un suit un lien de session qui lui a été envoyé par SMS, le client peut demander au serveur des informations d'identification pour participer à cette session spécifique. L'application peut en toute sécurité retirer la session de la file d'attente une fois qu'elle a été demandée. waiting une fois qu'elle a été demandée :
app.get('/answer/:sessionId', function(request, response) {
let sessionId = request.params.sessionId;
let index = waiting.indexOf(sessionId);
waiting.splice(index, 1);
response.send({
apiKey: process.env.OPENTOK_API_KEY,
sessionId: sessionId,
token: opentok.generateToken(sessionId)
});
}); Ajout d'une interface
Pour les tests, il est plus simple de conserver tout le code HTML sur une seule page. L'exemple index.html importe déjà client.js. Au-dessus de cette balise de script, vous voudrez également importer la bibliothèque du client OpenTok à partir des serveurs OpenTok :
<script src="https://static.opentok.com/v2/js/opentok.min.js"></script>Vous pouvez remplacer le contenu de la balise <body> par trois blocs : des boutons pour lancer le processus de demande ou de réponse, une pseudoforme pour collecter les numéros de téléphone des personnes qui souhaitent recevoir un texte, et les cibles de vos éléments vidéo :
<div id="buttons">
<a href="/ask" class="bigbutton" id="askBtn">Ask a Question</a>
<a href="/answer" class="bigbutton" id="answerBtn">Answer a Question</a>
</div>
<div id="addNumber">
No one has a question right now. Want a text when someone does?
<label>Phone number (e.g. 441234123456):
<input type="tel" id="phoneNumber" name="phoneNumber" />
</label>
<button id="phoneBtn">Text me!</button>
</div>
<div id="videos">
<div id="subscriber"></div>
<div id="publisher"></div>
</div>
Nous n'entrerons pas dans le CSS dans ce tutoriel, mais au minimum vous voudrez probablement cacher les boutons
#addNumberet#videoslors du premier chargement de la page. Vous pouvez ajouter cela et tout autre style à la feuille de style existante à l'adressestyle.css.
Configuration côté client
La première chose que vous voulez que votre script client fasse est de voir s'il y a un paramètre id dans l'URL. Cela indique que quelqu'un a suivi un lien dans un texte pour rejoindre une session de chat en cours. Si c'est le cas, vous pouvez immédiatement récupérer les informations d'identification nécessaires pour rejoindre la session à partir du point d'accès sur le serveur. /answer/:sessionId sur le serveur. La gestion de la réponse du serveur se fait dans l'une des deux fonctions suivantes, initializeSession ou handleErrordont nous parlerons dans une minute :
let params = new URLSearchParams(window.location.search);
let ongoingId = params.get('id');
if (ongoingId) {
fetch('/answer/' + ongoingId).then(function fetch(res) {
return res.json();
}).then(function fetchJson(json) {
initializeSession(json.apiKey, json.sessionId, json.token);
}).catch(function catchErr(error) {
handleError(error);
});
}Après avoir traité le cas moins courant où une personne souhaite rejoindre une session spécifique, vous pouvez mettre en place le script que vous utiliserez pour gérer les actions dans l'interface. C'est également un bon endroit pour définir handleError. Si vous le souhaitez, cette fonction peut être beaucoup plus complexe que sa forme actuelle, où elle se contente d'envoyer l'erreur à la console. Ensuite, vous pouvez sélectionner les éléments de premier niveau qui recevront une fonctionnalité dynamique. Si les boutons que vous avez sélectionnés existent, vous pouvez leur attribuer des gestionnaires de clics :
function handleError(error) {
if (error) {
console.error(error);
}
}
var askBtn = document.querySelector('#askBtn');
var answerBtn = document.querySelector('#answerBtn');
var addPhone = document.querySelector('#addNumber');
var phoneBtn = document.querySelector('#phoneBtn');
if (askBtn) askBtn.onclick = askQuestion;
if (answerBtn) answerBtn.onclick = answerQuestion;
if (phoneBtn) phoneBtn.onclick = addPhoneNumber; Initialisation d'une session
Le processus d'initialisation d'une session de questions-réponses commence par un clic sur les boutons Demander ou Répondre. Les gestionnaires de ces boutons, askQuestion et answerQuestionsont presque identiques. Ils suppriment d'abord l'action par défaut du lien, puis récupèrent les informations d'identification du chat à partir du point de terminaison approprié sur le serveur. S'il est possible de créer ou de rejoindre une session, initializeSession est appelé avec les informations d'identification. Dans le cas de answerQuestionsi personne ne pose de question, l'assistant voit à la place l'option de fournir son numéro de téléphone :
function askQuestion(e) {
e.preventDefault();
fetch('/ask').then(function fetch(res) {
return res.json();
}).then(function fetchJson(json) {
initializeSession(json.apiKey, json.sessionId, json.token);
}).catch(function catchErr(error) {
handleError(error);
});
}
function answerQuestion(e) {
e.preventDefault();
fetch('/answer').then(function fetch(res) {
return res.json();
}).then(function fetchJson(json) {
if (json.wait) {
addPhone.style.display = 'block';
return;
}
initializeSession(json.apiKey, json.sessionId, json.token);
}).catch(function catchErr(error) {
handleError(error);
});
}La fonction initializeSession est peut-être la logique la plus complexe de toute l'application. Étonnamment, l'API OpenTok simplifie en fait la logique nécessaire. Elle se charge de la coordination entre les auditeurs de la session de chat et les éléments du DOM, de sorte que les tâches de bas niveau, comme la création d'un élément <video> et l'assignation de sa source se déroulent en coulisses.
La fonction crée d'abord une instance de la session en fournissant à l'API OpenTok la clé API et l'ID de la session.
Les méthodes statiques de l'API OpenTok côté client sont disponibles sous la variable
OT(variable). Vous pouvez ignorer les plaintes de l'éditeur concernant le fait queOTn'est pas définie. Cependant, pour une application plus robuste, il serait préférable de faire un contrôle d'erreur et de vérifier queOTest est en fait définie. Inversement, vous ne voulez pas définir trop de choses en assignant n'importe quoi d'autre dans votre code à cette variable.OTen assignant n'importe quel autre élément de votre code à cette variable, à moins que vous ne changiez d'abord le nom de l'objet par défaut de l'API.
Le premier gestionnaire dont vous avez besoin est celui de l'événement streamCreated (événement). Lorsqu'un flux est créé dans la session en cours, il apparaît dans l'élément avec l'ID subscriber. Vous pouvez également ajouter un gestionnaire pour notifier le client s'il est déconnecté de la session.
Ensuite, définissez quelques propriétés pour le flux vidéo de l'éditeur. Le client est toujours l'éditeur de son propre point de vue. Sa vidéo aura une taille de 100 % et sera annexée à l'élément publisher et sera ajoutée à l'élément
Avec le minimum de gestionnaires d'événements et de configuration en place, vous pouvez vous connecter à la session et ajouter le flux de l'éditeur au client :
function initializeSession(apiKey, sessionId, token) {
var session = OT.initSession(apiKey, sessionId);
// Subscribe to a newly created stream
session.on('streamCreated', function streamCreated(event) {
var subscriberOptions = {
insertMode: 'append',
width: '100%',
height: '100%'
};
session.subscribe(event.stream, 'subscriber', subscriberOptions, handleError);
});
session.on('sessionDisconnected', function sessionDisconnected(event) {
console.log('You were disconnected from the session.', event.reason);
});
// initialize the publisher
var publisherOptions = {
insertMode: 'append',
width: '100%',
height: '100%'
};
var publisher = OT.initPublisher('publisher', publisherOptions, handleError);
// Connect to the session
session.connect(token, function callback(error) {
if (error) {
handleError(error);
} else {
// If the connection is successful, publish the publisher to the session
session.publish(publisher, handleError);
}
});
} Enregistrement d'un numéro de téléphone
À ce stade, vous devriez disposer d'un service d'assistance téléphonique opérationnel. Si quelqu'un clique sur le bouton Poser une question et que quelqu'un d'autre arrive peu après et clique sur Répondre à une question, les deux parties devraient se retrouver en chat vidéo et, avec un peu de chance, être en mesure de résoudre toutes leurs énigmes JavaScript. La seule chose qu'il reste à ajouter est la possibilité d'envoyer un numéro de téléphone par SMS au cas où il n'y aurait pas de question pour le moment, mais qu'une question surviendrait plus tard.
Le gestionnaire addPhoneNumber est, comme les gestionnaires de boutons, une simple suppression de l'événement par défaut et une recherche. Dans ce cas, vous allez POST au serveur, en fixant la valeur Content-Type à application/json et en transformant en chaîne la valeur du champ #phoneNumber et la valeur du champ Si cela réussit, vous masquerez à nouveau le champ de saisie du numéro de téléphone :
function addPhoneNumber(e) {
e.preventDefault();
fetch('/text', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({phone: document.querySelector('#phoneNumber').value})
}).then(() => {
addPhone.style.display = 'none';
}).catch(function catchErr(error) {
handleError(error);
});
}
Prochaines étapes
Il existe de nombreuses fonctionnalités différentes que vous pourriez ajouter à votre hotline, et de nombreuses hotlines différentes que vous pourriez créer. Il pourrait être intéressant pour les utilisateurs de voir combien de personnes attendent des questions ou des réponses, et la possibilité de se reconnecter à une session interrompue ajouterait de la robustesse à l'ensemble.
Puisque vous utilisez déjà l'API Nexmo, vous pourriez ajouter l'option de faire un simple Voice chat. Et puisque vous utilisez déjà OpenTok, vous pourriez certainement envisager d'ajouter des fonctionnalités telles que le partage d'écran ou l'option d'archiver questions communes.
Vous pouvez en savoir plus sur ce que vous pouvez faire avec OpenTok dans le TokBox Developer Centeret vous pouvez voir et remixer le code de cet exemple sur Glitch :
Partager:
Je suis développeur JavaScript et éducateur de développeurs chez Vonage. Au fil des ans, j'ai été très intéressé par les modèles, Node.js, les applications Web progressives et les stratégies offline-first, mais ce que j'ai toujours aimé, c'est une API utile et bien documentée. Mon objectif est de faire en sorte que votre expérience de l'utilisation de nos API soit la meilleure possible.