[JavaScript, Программирование, Конференции, Видеоконференцсвязь] Видеочат с возможностью совместного редактирования текста при помощи Twilio Sync (перевод)

Автор Сообщение
news_bot ®

Стаж: 6 лет 9 месяцев
Сообщений: 27286

Создавать темы news_bot ® написал(а)
30-Июн-2021 20:32


Представьте, что вам нужно создать видеочат, функционал которого должен находиться под вашим контролем, например для закрытой группы людей со своими специфическими требованиями. При этом чат нужен вчера, начинать писать его с нуля уже поздно. В этом материале, переводом которого мы решили поделиться к старту курса о Frontend-разработке, рассказывается, как разработать программируемый видеочат на основе Twilio. В статье вы найдёте две ветки кода на Github, первая содержит простую основу чата, о которой пойдёт речь в материале, а вторая — завершённый пример чата.ПодготовкаЧто вам будет нужно:
  • Бесплатная учётная запись Twilio. Если вы зарегистрируетесь здесь, вы получите 10 долларов в качестве кредита Twilio при переходе на платную учётную запись.
  • Node.js (версия 14.16.1 или выше) и npm.
  • Код из этого репозитория.
Скачайте и запустите код видеоблокнотаЧтобы скачать код, выберите место на вашем компьютере, где вы хотите работать с проектом. Затем откройте окно терминала и выполните следующую команду, чтобы клонировать ветку start:
git clone -b start https://github.com/adjeim/video-note-collab.git
Затем перейдите в корневой каталог проекта и установите необходимые зависимости, выполнив следующие команды:
cd video-note-collab
npm install
Скопируйте файл .env для переменных среды такой командой:
cp .env.template .env
Затем откройте файл .env в редакторе кода и замените значения переменных своими учётными данными:
TWILIO_ACCOUNT_SID
TWILIO_SYNC_SERVICE_SID
TWILIO_API_KEY_SID
TWILIO_API_KEY_SECRET
Найти свои учётные данные вы можете в консоли Twilio, на странице Twilio Sync Service и на странице Twilio API Keys. В качестве значения переменной TWILIO_SYNC_SERVICE_SID можно использовать SID по умолчанию. Теперь, когда вы ввели свои учётные данные, запустите сервер Express:
npm start
Если вы перейдёте по адресу http://localhost:3000/ в своём браузере, то увидите заметку:
Протестируйте приложение, набрав несколько слов в блокноте. При вводе пробела, клавиши ввода или знаков препинания запускается синхронизация. Если вы откроете второе окно браузера по адресу http://localhost:3000/ и одновременно посмотрите на них, вы должны увидеть, что текст, который вы вводите в одном окне, отображается и в другом:
Как это происходит? Это приложение использует Twilio Sync для синхронизации состояния и данных между браузерами и устройствами в режиме реального времени. Здесь у вас есть документ Sync, который называется notepad. Когда страница загружается, создаётся новый токен доступа, который передаётся Sync клиенту. Если документ существует, его содержимое загружается в <textarea>. Приложение отслеживает обновления документа, обновляя положение курсора и содержимое блокнота. Если вы откроете инструменты разработчика своего браузера, вы также сможете увидеть изменения в контенте, который записывается в консоль.Идея здесь аналогична идее других инструментов совместной работы с заметками, таким как Google Docs или Notion. С помощью этого типа приложения вы можете вместе с другим человеком просматриватьодин и тот же документ и вместе редактировать его в режиме реального времени. Запустите приложение — и переходите к следующему шагуОбновите макет приложенияПервое, что вам нужно сделать, — это немного обновить макет вашего приложения. Если вы прямо сейчас откроете public/index.html в редакторе кода, то увидите, что Tailwind CSS и Twilio Sync уже подключены в проект. Обновите элемент <head>, добавив в него библиотеку Twilio Video, как показано в приведённом ниже коде:
<html>
  <head>
    <meta name='viewport' content='width=device-width, initial-scale=1.0' />
    <link href='https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css' rel='stylesheet'>
    <script type="text/javascript" src="https://media.twiliocdn.com/sdk/js/sync/v2.0/twilio-sync.min.js"></script>
    <script src='https://sdk.twilio.com/js/video/releases/2.15.0/twilio-video.min.js'></script>
    <title>Video Collaboration with Notes</title>
  </head>
Обновите элемент <body>. Сначала добавьте элемент <form>, в котором пользователь может ввести своё имя и нажать кнопку, чтобы присоединиться к комнате.
<body class='bg-grey-100 p-10 flex flex-wrap container'>
    <form id='login' class='w-full max-h-20 flex items-center py-2'>
        <input class='appearance-none bg-transparent border-b border-green-500 mr-3 py-1 px-2 focus:outline-none'
            id='identity' type='text' placeholder='Enter your name...' required>
        <button id='joinOrLeaveRoom' class='bg-green-500 hover:bg-green-700 text-white py-1 px-4 rounded' type='submit'>
          Join Video Call
        </button>
    </form>
    <textarea id='notepad' class='h-44 w-full shadow-lg border rounded-md p-3 sm:mx-auto sm:w-1/2'></textarea>
Замените элемент <textarea>. В этом проекте вы отключите взаимодействие с документом и установите для него серый цвет фона при первой загрузке приложения.
</form>
    <textarea disabled id='notepad' class='bg-gray-200 h-140 w-6/12 shadow-lg border rounded-md p-3 sm:mx-auto sm:w-1/2'></textarea>
Затем чуть ниже <textarea> добавьте элемент <div> для вывода видео  участников:
<textarea disabled id='notepad' class='bg-gray-200 h-140 w-6/12 shadow-lg border rounded-md p-3 sm:mx-auto sm:w-1/2'></textarea>
    <div id='container' class='w-5/12  bg-green-100'>
      <div id='participantsContainer'>
        <div id='localParticipant'>
          <div id='localVideoTrack' class='participant'></div>
        </div>
        <div id='remoteParticipants'>
          <!-- Remote participants will be added here as they join the call -->
        </div>
      </div>
    </div>
Теперь, когда у вас в интерфейсе есть место для отображения видео участников, пришло время добавить отображающий это видео код.Обновите генерацию токена доступаЕсли вы откроете index.js в своём редакторе кода, вы увидите, что у вас уже есть код для предоставления токена доступа и что к этим токенам доступа будет добавлен SyncGrant. Чтобы задействовать видео, вам также понадобится VideoGrant.Под вашей константой для SyncGrant также укажите константу для VideoGrant. Пока вы в этой части кода, убедитесь, что ваше приложение может парсить JSON из тела запроса при помощи функции express.json():
const AccessToken = require('twilio').jwt.AccessToken;
const SyncGrant = AccessToken.SyncGrant;
const VideoGrant = AccessToken.VideoGrant;
app.use(express.json());
Обновите свой роутер для получения токена, чтобы он был асинхронным и чтобы получить идентификационные данные пользователя и имя видеокомнаты из запроса POST. Здесь вы также добавите VideoGrant к токену доступа.
app.post('/token', async (req, res) => {
  if (!req.body.identity || !req.body.room) {
    return res.status(400);
  }
  // Get the user's identity from the request
  const identity = req.body.identity;
  // Create a 'grant' identifying the Sync service instance for this app.
  const syncGrant = new SyncGrant({
      serviceSid: process.env.TWILIO_SYNC_SERVICE_SID
  });
  // Create a video grant
  const videoGrant = new VideoGrant({
    room: req.body.room
  })
  // Create an access token which we will sign and return to the client,
  // containing the grant we just created and specifying their identity.
  const token = new AccessToken(
      process.env.TWILIO_ACCOUNT_SID,
      process.env.TWILIO_API_KEY_SID,
      process.env.TWILIO_API_KEY_SECRET,
  );
  token.addGrant(syncGrant);
  token.addGrant(videoGrant);
  token.identity = identity;
  // Serialize the token to a JWT string and include it in a JSON response
  res.send({
      identity: identity,
      token: token.toJwt()
  });
});

Теперь ваш токен предоставит пользователям вашего приложения доступ к синхронизации и к видео. Теперь, когда вы обновили серверную часть приложения, пора вернуться на клиентскую сторону и отобразить видео в окне браузера.Подключение и вывод видео участниковВернитесь в public/index.html в редакторе кода. Посмотрите на код в последнем теге <script> в конце файла. Вы увидите, что когда приложение загружается в браузере, этот код получает токен доступа из вашего запроса на токен, затем подключает клиент синхронизации и обновляет блокнот. Чтобы добавить видео в этот проект, нужно изменить этот код таким образом, чтобы приложение получило токен после того, как пользователь введёт своё имя и нажмёт кнопку «Join Video Call» в пользовательском интерфейсе. Затем этот токен будет использоваться для подключения пользователя к синхронизированному блокноту и видеозвонку. Чуть ниже вашей переменной notepad добавьте ещё несколько переменных, чтобы упростить обращение к другим элементам в вашем пользовательском интерфейсе:
<script>
  const notepad = document.getElementById('notepad');
  const localVideoTrack = document.getElementById('localVideoTrack');
  const login = document.getElementById('login');
  const identityInput = document.getElementById('identity');
  const joinLeaveButton = document.getElementById('joinOrLeaveRoom');
  const localParticipant = document.getElementById('localParticipant');
  const remoteParticipants = document.getElementById('remoteParticipants');
  let connected = false;
  let room;
  let syncDocument;
  let twilioSyncClient;
Теперь вы сможете обращаться к различным частям видеочата, а также отслеживать, подключён ли локальный пользователь к видеозвонку. Вы также сможете отслеживать, открыт ли синхронизированный документ, с которым пользователь может взаимодействовать. Чтобы сделать предварительный просмотр видеозвонка, добавьте функцию addLocalVideo чуть ниже списка переменных, которые вы обновили выше:
const addLocalVideo = async () => {
    const videoTrack = await Twilio.Video.createLocalVideoTrack();
    const trackElement = videoTrack.attach();
    localVideoTrack.appendChild(trackElement);
  };
Вызовите эту функцию в конце файла, непосредственно перед закрывающим тегом <script>:
addLocalVideo();
</script>
Затем создайте новую функцию с именем connectOrDisconnect, которая будет обрабатывать событие, когда пользователь нажимает кнопку «Join Video Call». Если пользователь ещё не подключён к звонку, эта функция подключит их. Если пользователь уже подключён, эта функция отключит его. Добавьте следующий код чуть ниже функции addLocalVideo:
const connectOrDisconnect = async (event) => {
    event.preventDefault();
    if (!connected) {
      const identity = identityInput.value;
      joinLeaveButton.disabled = true;
      joinLeaveButton.innerHTML = 'Connecting...';
      try {
        await connect(identity);
      } catch (error) {
        console.log(error);
        alert('Failed to connect to video room.');
        joinLeaveButton.innerHTML = 'Join Video Call';
        joinLeaveButton.disabled = false;
      }
    }
    else {
      disconnect();
    }
  };
Непосредственно перед закрывающим тегом <script> добавьте ещё один слушатель событий, на этот раз в форму входа. Этот слушатель будет вызывать connectOrDisconnect всякий раз, когда пользователь отправляет форму:
// Add listener
  notepad.addEventListener('keyup', (event) => {
    // Define array of triggers to sync (space, enter, and punctuation)
    // Otherwise sync will fire every time
    const syncKeys = [32, 13, 8, 188, 190];
    if (syncKeys.includes(event.keyCode)) {
      syncNotepad(twilioSyncClient);
    }
  })
  login.addEventListener('submit', connectOrDisconnect);
Затем замените блок fetch('/token') следующей функцией подключения, которая примет идентификатор, переданный в форму, получит токен для этого пользователя с сервера, загрузит и включит документ и подключит этого локального пользователя в видеочат:
const connect = async (identity) => {
    const response = await fetch('/token', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({'identity': identity, room: 'My Video Room'})
    });
    const data = await response.json();
    const token = data.token;
    // Set up sync document
    twilioSyncClient = new Twilio.Sync.Client(token);
    notepad.disabled = false;
    notepad.classList.remove('bg-gray-200');
    syncDocument = await twilioSyncClient.document('notepad');
    // Load the existing Document
    notepad.value = syncDocument.data.content || '';
    // Listen to updates on the Document
    syncDocument.on('updated', (event) => {
      // Update the cursor position
      let cursorStartPos = notepad.selectionStart;
      let cursorEndPos = notepad.selectionEnd;
      notepad.value = event.data.content;
      // Reset the cursor position
      notepad.selectionEnd = cursorEndPos;
      console.log('Received Document update event. New value:', event.data.content);
    })
    // Set up the video room
    room = await Twilio.Video.connect(token);
    const identityDiv = document.createElement('div');
    identityDiv.setAttribute('class', 'identity');
    identityDiv.innerHTML = identity;
    localParticipant.appendChild(identityDiv);
    room.participants.forEach(participantConnected);
    room.on('participantConnected', participantConnected);
    room.on('participantDisconnected', participantDisconnected);
    connected = true;
    joinLeaveButton.innerHTML = 'Leave Video Call';
    joinLeaveButton.disabled = false;
    identityInput.style.display = 'none';
  };
Как только локальный участник подключится к звонку, эта видеокомната будет назначена глобальной переменной для room. Видео локального пользователя будет отображаться в пользовательском интерфейсе, и слушатели событий будут отслеживать, когда другие участники присоединяются к видеовстрече или выйдут из неё. Кнопка «Join Video Call» также изменится на «Leave Video Call», а поле ввода для имени будет скрыто. Теперь, когда вы добавили функцию подключения, добавьте функцию отключения чуть ниже:
const disconnect = () => {
    room.disconnect();
    let removeParticipants = remoteParticipants.getElementsByClassName('participant');
    while (removeParticipants[0]) {
      remoteParticipants.removeChild(removeParticipants[0]);
    }
    joinLeaveButton.innerHTML = 'Join Video Call';
    connected = false;
    identityInput.style.display = 'inline-block';
    localParticipant.removeChild(localParticipant.lastElementChild);
    syncDocument.close();
    twilioSyncClient = null;
    notepad.value = '';
    notepad.disabled = true;
    notepad.classList.add('bg-gray-200');
  };
Функция disconnect будет обрабатывать отключение участника от видеозвонка, когда он нажимает кнопку «Leave Video Call». Она также будет проходить через других участников видеозвонка и удалять видео из пользовательского интерфейса для отключённого участника. Состояние подключения снова устанавливается на false, поле ввода имени пользователя появляется снова, а кнопка «Leave Video Call» меняется на «Join Video Call». Кроме того, блокнот будет очищен и отключён для локального участника, как только кто-то отключится от видеозвонка, он также будет отключён от общего блокнота.Затем вы захотите поработать с тем, что происходит, когда удалённые участники подключаются к звонку или отключаются от него. Начните с добавления функции ParticipantConnected, которая создаст новый <div> для подключённого участника, показывая имя пользователя участника в качестве его идентификатора и прикрепляя их видео и аудиодорожки к <div>, если локальный участник подписан на них.Эта функция также создаёт обработчики событий для управления действиями по подписке, относящимися к аудио- и видеодорожкам участников. Если удалённый участник отключает свой аудио- или видеопоток, хочется иметь возможность реагировать на это событие и при необходимости подключать или отключать эти дорожки. Добавьте функцию participantConnected чуть ниже вашей функции отключения в public/index.html:
const participantConnected = (participant) => {
    const participantDiv = document.createElement('div');
    participantDiv.setAttribute('id', participant.sid);
    participantDiv.setAttribute('class', 'participant');
    const tracksDiv = document.createElement('div');
    participantDiv.appendChild(tracksDiv);
    const identityDiv = document.createElement('div');
    identityDiv.setAttribute('class', 'identity');
    identityDiv.innerHTML = participant.identity;
    participantDiv.appendChild(identityDiv);
    remoteParticipants.appendChild(participantDiv);
    participant.tracks.forEach(publication => {
      if (publication.isSubscribed) {
        trackSubscribed(tracksDiv, publication.track);
      }
    });
    participant.on('trackSubscribed', track => trackSubscribed(tracksDiv, track));
    participant.on('trackUnsubscribed', trackUnsubscribed);
  };
Пришло время добавить функцию ParticipantDisconnected для ситуации, когда удалённый участник покидает видеозвонок. Это функция, которая находит участника по его sid (уникальному идентификатору) и удаляет его div из DOM. Добавьте функцию participantDisconnected сразу под вашей функцией ParticipantConnected:
const participantDisconnected = (participant) => {
    document.getElementById(participant.sid).remove();
  };
А теперь добавим код для ситуации, когда локальный участник подписывается на аудио- или видеодорожки удалённого участника или отписывается от них. Добавьте следующие функции trackSubscribed и trackUnsubscribed в public/index.html чуть ниже вашего кода для participantDisconnected:
const trackSubscribed = (div, track) => {
    const trackElement = track.attach();
    div.appendChild(trackElement);
  };
  const trackUnsubscribed = (track) => {
    track.detach().forEach(element => {
      element.remove()
    });
  };
У вас есть весь код проекта. Теперь протестируем блокнот с видео.Тестирование вашего приложенияПерейдите по адресу http://localhost:3000/. Вы должны увидеть сайт, похожий на показанный ниже, с блокнотом слева и видеопотоком локального участника справа:
Введите своё имя в поле ввода и нажмите «Join Video Call». Вы увидите своё имя под видео. Если хотите, можете попробовать набрать текст в блокноте. Откройте другую вкладку браузера по адресу http://localhost:3000/ и присоединитесь к видеозвонку под другим именем. Как только вы это сделаете, вы увидите два изображения, а это означает, что вы можете общаться друг с другом и делиться блокнотом:
Если вы введёте текст в блокнот на одной вкладке, а затем переключитесь на другую, вы увидите, что текст между ними синхронизирован.Что будет дальше с инструментом для совместной работы с заметками?У этого блокнота очень много возможностей: от совместной работы над письменным проектом до совместного ведения заметок во время видеовстречи. Чтобы просмотреть весь код, пройдите в основную ветку этого репозитория GitHub.Вот так просто сегодня можно создать видеочат в вебе. Это означает, что веб в силу универсальности продолжает развиваться и, конечно, он давно уже перестал быть просто гипертекстом — удобством для чтения научных публикаций, как это было на заре его истории. Если вы не хотите оставаться в стороне от развития веб-технологий, то можете обратить внимание на наш курс о Frontend-разработке, а если вам не хочется ограничиваться фронтендом и есть желание понимать сеть глуюже, то вы можете присмотреться к нашему курсу о Fullstack-разработке на Python, где студенты получают все практические и теоретические знания, необходимые для начала карьеры разработчика на этом языке.
Узнайте, как прокачаться и в других специальностях или освоить их с нуля: Другие профессии и курсыПРОФЕССИИ КУРСЫ
===========
Источник:
habr.com
===========

===========
Автор оригинала: Mia Adjei
===========
Похожие новости: Теги для поиска: #_javascript, #_programmirovanie (Программирование), #_konferentsii (Конференции), #_videokonferentssvjaz (Видеоконференцсвязь), #_skillfactory, #_twilio, #_js, #_razrabotka (разработка), #_konferentsii (конференции), #_videosvjaz (видеосвязь), #_sinhronizatsija (синхронизация), #_open_source, #_github, #_svjaz (связь), #_blog_kompanii_skillfactory (
Блог компании SkillFactory
)
, #_javascript, #_programmirovanie (
Программирование
)
, #_konferentsii (
Конференции
)
, #_videokonferentssvjaz (
Видеоконференцсвязь
)
Профиль  ЛС 
Показать сообщения:     

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы

Текущее время: 22-Ноя 02:45
Часовой пояс: UTC + 5