https://a.storyblok.com/f/270183/37159/4d6a318bb4/blog_node-js_svelte_video_1200x600.png

Crie um chat com Video de ajuda usando Node.js e Svelte

Publicado em December 16, 2020

Tempo de leitura: 9 minutos

Um caso de uso como um chat de ajuda por Video para o seu site é um excelente argumento a favor de uma estrutura de front-end. Talvez o restante do site não tenha nada a ver com o chat por Video, ou talvez você queira usar o chat em vários lugares ou com várias configurações. Por diversos motivos, esse é o tipo de recurso que você provavelmente vai querer desenvolver como um componente.

O Svelte, que está entre os frameworks de front-end mais recentes, pode ser uma opção mais acessível. Se você ainda não se comprometeu com um framework, talvez seja mais rápido começar com algo que utilize HTML, CSS e JavaScript de uma maneira tão familiar. E, dada a variedade de elementos necessários para fazer um Video funcionar, ter menos coisas para aprender é uma vantagem útil para este exemplo.

Pré-requisitos

Para começar um novo projeto em Svelte, a recomendação é usar o o degit, uma ferramenta prática que baixa e descompacta modelos de aplicativos de Applications com facilidade. Você pode criar um novo projeto Svelte usando npx:

npx degit sveltejs/template video-help-chat

Depois de obter sua cópia, execute npm install para instalar as dependências.

Agora você pode acessar o video-help-chat diretório e verá a estrutura básica de um novo projeto Svelte. Antes de começar a trabalhar no código propriamente dito, você precisará de algumas coisas para fazer o chat por vídeo funcionar:

Se você não tiver um Account na Video API da Vonage, precisará primeiro se inscrever para um período de teste. Todas as ferramentas para criar seu servidor de Video podem ser instaladas a partir do npm:

npm -i opentok express concurrently dotenv

Svelte e Express, juntos

A função “Simultaneamente” permite executar vários comandos de uma só vez a partir de um único script no seu package.json. Você pode usá-lo para iniciar seu servidor Express e, ao mesmo tempo, executar o Rollup para recompilar o Svelte caso haja alguma alteração. Como você já tem comandos scripts para lidar com o Svelte, você pode empilhar scripts do npm, adicionando um novo script que execute os já existentes:

"scripts": {
    "build": "rollup -c",
    "dev": "rollup -c -w",
    "start": "sirv public",
    "serve": "concurrently \"node server.js\" \"npm run dev\""
  },

Configurando suas credenciais

É recomendável criar um local seguro para sua chave e seu segredo de API logo de início. Crie um .env arquivo para armazenar esses dados e quaisquer outras informações confidenciais. Antes de fazer o commit do seu código, certifique-se de adicionar o arquivo ao .gitignore para que ele não seja acidentalmente enviado. Se você hospedar esse código posteriormente, seu provedor de hospedagem provavelmente oferecerá uma maneira segura de você repovoar o .env arquivo no servidor.

Por enquanto, você só precisa de duas propriedades em .env: sua chave e seu segredo da Video API do Vonage. Ambos devem estar entre aspas, sem espaços:

VONAGE_VIDEO_API_KEY="12345678" VONAGE_VIDEO_SECRET="12a3b4c567d89e0f1234567890ab12345678c901"

Servidor

Seu servidor utilizará as credenciais que você forneceu para criar um cliente da Video API do Vonage.

A Video API da Vonage era conhecida anteriormente como OpenTok. O nome ainda é usado em alguns códigos, e continuaremos a usá-lo aqui para que o código se pareça mais com o de nossos tutoriais anteriores.

Comece importando o Express e criando o aplicativo Express. Em seguida, você pode criar uma rota para /chat. É comum ver páginas estáticas sendo tratadas na parte superior de um servidor Express, mas aqui você vai tratá-las quase no final. Isso serve para limitar a responsabilidade que devolvemos ao lado Svelte da aplicação, para que ele não tente lidar com nossos endpoints do servidor. Por fim, você pode configurar o servidor para escutar na porta 5000.

O /chat endpoint é onde tudo de interessante acontece. Essa função retornará as credenciais necessárias para criar o chat de vídeo no front-end. Ela também gerencia a sessão de chat de vídeo de forma bem básica, retornando a sessão existente ou criando uma nova caso não haja nenhuma.

require('dotenv').config();
const express = require('express');
const app = express();
app.use(express.json());

let sessionId;

app.get('/chat', function(request, response) {
  if (sessionId) {
    response.send({
      apiKey: process.env.VONAGE_VIDEO_API_KEY,
      sessionId: sessionId,
      token: opentok.generateToken(sessionId)
    });
  } else {
    opentok.createSession(function(err, session) {
      sessionId = session.sessionId;
      
      response.send({
        apiKey: process.env.VONAGE_VIDEO_API_KEY,
        sessionId: sessionId,
        token: opentok.generateToken(sessionId)
      });
    });
  } 
});

app.use(express.static('public'));
app.get('/', function(request, response) {
  response.sendFile(__dirname + '/public/index.html');
});

app.listen(5000);

Para começar a integrar este exemplo a um site real, a sessionId variável acima é o seu ponto de entrada. Você sempre pode criar uma nova sessão a partir do /chat ponto de extremidade e adicionar os IDs a uma pilha, em vez de a uma única variável. Sua equipe responsável por atender aos chats de vídeo poderá então acessar esses IDs de sessão para participar das chamadas em espera.

Cliente

Seu aplicativo modelo deve incluir um App.svelte arquivo na pasta /public/src. Deve ser possível executá-lo e testá-lo agora mesmo, abrindo seu terminal e digitando:

npm run serve

Você deverá ver a página “hello world” do Svelte ao abrir seu navegador e acessar “localhost:5000”.

Enquanto você estiver App.svelte aberto, vá em frente e adicione referências ao componente que vamos criar a seguir. Primeiro, importe o componente, que vamos chamar de Chat.svelte:

<script>
	export let name;

	import Chat from './Chat.svelte';
</script>

Na parte inferior da sua página, acima da <style> , adicione o próprio componente:

<main>
	<h1>Hello {name}!</h1>
	<p>Visit the <a href="https://svelte.dev/tutorial">Svelte tutorial</a> to learn how to build Svelte apps.</p>
</main>

<Chat/>

Componente de bate-papo

É possível que o aplicativo em execução esteja apresentando alguns erros neste momento; portanto, adicione rapidamente o Chat.svelte arquivo em /public/src. Já que está fazendo isso, você também pode adicionar ChatButton.svelte e VideoChat.svelte arquivos.

O componente Chat servirá apenas como um contêiner para o chat, que possui dois estados. Inicialmente, será exibido ao usuário um link para iniciar o chat. Ao clicar no link, ele entrará no próprio chat por Video. O componente Chat gerencia a alternância entre os dois, que serão encapsulados em seus próprios componentes.

Se você ainda não trabalhou com muitos componentes do Svelte, este é um bom exemplo minimalista para dar uma olhada. Você pode ver que se trata apenas de JavaScript, HTML e CSS. Ele se parece muito com uma página HTML estática, sem o conteúdo e as metainformações:

<script>
  export let collapsed = true;

  import ChatButton from './ChatButton.svelte';
  import Conversation from './VideoChat.svelte';
</script>


<div class="chatContainer" class:expanded="{!collapsed}">
  {#if collapsed}
    <ChatButton bind:showButton={collapsed}/>
  {:else}
    <Conversation/>
  {/if}
</div>

<style>
  .chatContainer {
    position: fixed;
    bottom: 2em;
    right: 2em;
  }
  .expanded {
    width: auto;
    left: 2em;
    min-height: 10em;
  }
</style>

Como se trata apenas de um contêiner para o estado, faz sentido que o componente tenha apenas uma propriedade, collapsed. Ele importa os outros dois componentes e determina qual deles exibir usando uma estrutura condicional na marcação. Por fim, um código CSS posiciona o contêiner no canto inferior direito. Se o chat estiver aberto, uma classe CSS condicional ampliará o contêiner.

Funcionalidade do botão de bate-papo

A maior parte do componente ChatButton consiste em CSS decorativo para fazer com que ele se pareça com um pequeno balão de diálogo. No entanto, ele também é um exemplo de como o Svelte lida com eventos e se comunica entre componentes.

O componente exporta apenas uma propriedade, showButton. Ela não é usada dentro do componente, mas sim em seu pai. Ela foi vinculada à collapsed propriedade do componente Chat na marcação do Chat:

    <ChatButton bind:showButton={collapsed}/>

Quando o botão é clicado, a openChat função é chamada, invertendo o valor de showButton para “false” e, consequentemente, definindo collapsed como falso no pai. Isso abrirá a interface de usuário do chat.

<script>
  export let showButton = true;

  function openChat() {
    showButton = false;
  }
</script>

<button on:click={openChat}>Chat now</button>

<style>
  button {
    position: relative;
    background: #ac57c8;
    border: none;
    border-radius: 10px;
    padding: 20px;
    color: #fff;
    font-weight: bold;
    cursor: pointer;
    box-shadow: 5px 15px 10px rgba(0,0,0,.5);
  }
  button:hover, button:active {
    color: #83C4F1;
  }
  button:after {
    content: '';
    position: absolute;
    right: 0;
    top: 60%;
    width: 0;
    height: 0;
    border: 20px solid transparent;
    border-left-color: #ac57c8;
    border-right: 0;
    border-bottom: 0;
    margin-top: -10px;
    margin-right: -20px;
  }
</style>

Video Chat

Deixamos o melhor (o JavaScript, é claro) para o final. Não há muito HTML e CSS no componente VideoChat. Há marcadores de posição para o emissor e o receptor (as visualizações de você e da pessoa com quem está conversando), além de mais estilos para os balões de diálogo no contêiner. O resto é JS.

Para criar um bate-papo por Video, você precisará fazer algumas coisas:

  • Obter a sessão (seja ela recém-criada ou em andamento, isso não importa para o cliente) do servidor

  • Inicialize-o

  • Fique atento à criação de um stream e, em seguida, inscreva-se nele

  • Fique atento para saber quando a sessão for desconectada

  • Inicializar a transmissão (envio de Video e áudio)

  • Conecte-se à sessão e publique nela

A maior parte do trabalho será realizada em uma função chamada initSession, chamada assim que o cliente obtiver com sucesso uma sessão do servidor. Com a parte principal do initSession , o componente não é muito complexo. Ele usa fetch para obter a sessão e define um manipulador de erros. Em seguida, define os marcadores de posição para o chat de vídeo e o CSS para definir o layout:

<script>
  fetch('/chat').then(function fetch(res) {
    return res.json();
  }).then(function fetchJson(json) {
    if (json.error) {
      handleError(error);
    } else {
      initSession(json.apiKey, json.sessionId, json.token);
    }
  }).catch(function catchErr(error) {
    handleError(error);
  });

  function handleError(error) {
    if (error) {
      console.error(error);
    }
  }

  function initSession(apiKey, sessionId, token) {}
</script>


<div class="conversation">
  <div id="subscriber"></div>
  <div id="publisher"></div>
</div>

<style>
  .conversation {
    position: relative;
    width: auto;
    min-height: 10em;
    background: #ac57c8;
    border: none;
    border-radius: 10px;
    padding: 20px;
    box-shadow: 5px 15px 10px rgba(0,0,0,.5);
  }
  .conversation:after {
    content: '';
    position: absolute;
    right: 0;
    top: 60%;
    width: 0;
    height: 0;
    border: 20px solid transparent;
    border-left-color: #ac57c8;
    border-right: 0;
    border-bottom: 0;
    margin-top: -10px;
    margin-right: -20px;
  }
</style>

O conteúdo de initSession é composto principalmente por callbacks. Primeiro, você cria um ouvinte para streamCreated, e dentro dele define um objeto de opções e o utiliza para chamar session.subscribe(). Você também pode criar um ouvinte para sessionDisconnected. Atualmente, esse componente não fornece feedback ao seu pai, mas seria mais robusto se sinalizasse quando o bate-papo terminasse. O sessionDisconnected manipulador seria um bom lugar para fazer isso.

Você pode criar publisherOptions um visual idêntico ao seu subscriberOptions e basta indicar que o elemento de Video deve ser anexado ao seu contêiner com 100% de altura e largura. Em seguida, você pode inicializar o publisher.

Por fim, com seu editor pronto para uso, conecte-se à sessão com session.connect(). Assim que a conexão for estabelecida com sucesso, você poderá começar a publicar com session.publish().

function initSession(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);
      }
    });
  }

Experimente

Se o seu servidor estiver em execução o tempo todo, você deve conseguir ver parte ou todo o seu código funcionando na aba aberta do navegador. No entanto, provavelmente será necessário reiniciar o servidor. No terminal, encerre os processos pressionando Ctrl+C e, em seguida, reinicie o Express e o Svelte com npm run serve.

Abra ou volte para localhost:5000 no seu navegador. A maneira mais fácil de testar o chat é abrir outro navegador e acessar também localhost:5000. Isso não é muito sofisticado, mas o eco que você ouvir deve confirmar que o chat está funcionando.

Próximos passos

Agora que você já tem um chat básico, há muito mais coisas que você pode fazer com a Video API da Vonage. Ou você pode optar por manter os recursos limitados por enquanto e fazer algumas alterações na forma como o servidor fornece as sessões, para que os usuários possam “fazer perguntas” a partir dessa interface e os usuários internos possam “responder” a partir de outra.

Além disso, há muito mais coisas que você pode fazer com o Svelte, como mostrado em seu excelente tutorial. Se você estiver adicionando mais funcionalidades ao seu chat — talvez coletar o nome ou o e-mail do usuário —, essas ferramentas podem ser muito úteis.

Compartilhar:

https://a.storyblok.com/f/270183/250x250/f231d97f1b/garann-means.png
Garann MeansFormador de Desenvolvedores

Sou desenvolvedor de JavaScript e instrutor de desenvolvimento na Vonage. Ao longo dos anos, tenho me interessado muito por modelos, Node.js, aplicativos web progressivos e estratégias “offline-first”, mas o que sempre adorei de verdade é uma API útil e bem documentada. Meu objetivo é tornar a sua experiência com nossas APIs a melhor possível.