Создание приложения потоковой передачи кода в режиме реального времени с помощью Socket.IO и его размещение в Azure
Создание функции совместного создания в Microsoft Word в режиме реального времени может быть сложной задачей.
С помощью простых в использовании API Socket.IO оказался библиотекой для обмена данными между клиентами и сервером в режиме реального времени. Однако Socket.IO пользователи часто сообщают о трудностях при масштабировании подключений Socket.IO. С помощью Web PubSub для Socket.IO разработчики больше не должны беспокоиться об управлении постоянными подключениями.
Внимание
Необработанные строка подключения отображаются в этой статье только для демонстрационных целей.
Строка подключения содержит сведения об авторизации, требуемые для доступа приложения к службе Azure Web PubSub. Ключ доступа в строке подключения аналогичен паролю привилегированного пользователя для службы. В рабочих средах всегда защищать ключи доступа. Используйте Azure Key Vault для безопасного управления ключами и защиты подключения.WebPubSubServiceClient
Старайтесь не распространять ключи доступа среди других пользователей, жестко программировать их или где-то сохранять в виде обычного текста в открытом доступе для других пользователей. Меняйте свои ключи постоянно, если предполагаете, что они могут быть подобраны.
Обзор
В этой статье показано, как создать приложение, позволяющее кодировщику передавать действия по программированию аудитории. Вы создаете это приложение с помощью:
- Редактор Монако, редактор кода, который управляет Visual Studio Code.
- Express, веб-платформа Node.js.
- API, которые библиотека Socket.IO предоставляет для обмена данными в режиме реального времени.
- Узлы Socket.IO подключения, использующие Web PubSub для Socket.IO.
Готовое приложение
Готовое приложение позволяет пользователю редактора кода предоставлять доступ к веб-ссылке, с помощью которой пользователи могут просматривать ввод.
Для поддержания фокуса процедур и дайджестируемых в течение около 15 минут в этой статье определяются две роли пользователей и то, что они могут сделать в редакторе:
- Модуль записи, который может ввести в онлайн-редакторе и содержимое передается в поток
- Зрители, получающие содержимое в режиме реального времени, типизированные средством записи, и не могут редактировать содержимое.
Архитектура
Товар | Характер использования | Льготы |
---|---|---|
библиотека Socket.IO | Предоставляет механизм обмена данными с низкой задержкой и двунаправленным обменом данными между серверным приложением и клиентами | Простые в использовании API, охватывающие большинство сценариев обмена данными в режиме реального времени |
Web PubSub для Socket.IO | Узлы WebSocket или постоянные подключения на основе опроса с клиентами Socket.IO | Поддержка 100 000 одновременных подключений; упрощенная архитектура приложения |
Необходимые компоненты
Чтобы выполнить все действия, описанные в этой статье, вам потребуется:
- Учетная запись Azure. Если у вас еще нет подписки Azure, создайте бесплатную учетную запись Azure, прежде чем начинать работу.
- Azure CLI (версия 2.29.0 или более поздней версии) или Azure Cloud Shell для управления ресурсами Azure.
- Базовое знакомство с API-интерфейсами Socket.IO.
Создание веб-pubSub для ресурса Socket.IO
Используйте Azure CLI для создания ресурса:
az webpubsub create -n <resource-name> \
-l <resource-location> \
-g <resource-group> \
--kind SocketIO \
--sku Free_F1
Получение строка подключения
Строка подключения позволяет подключаться к Web PubSub для Socket.IO.
Выполните указанные ниже команды. Сохраните возвращенные строка подключения где-то, так как вам потребуется при запуске приложения далее в этой статье.
az webpubsub key show -n <resource-name> \
-g <resource-group> \
--query primaryKey \
-o tsv
Написание кода на стороне сервера приложения
Начните писать код приложения, работая на стороне сервера.
Создание HTTP-сервера
Создайте проект Node.js:
mkdir codestream cd codestream npm init
Установите серверный пакет SDK и Express:
npm install @azure/web-pubsub-socket.io npm install express
Импорт обязательных пакетов и создание HTTP-сервера для обслуживания статических файлов:
/*server.js*/ // Import required packages const express = require('express'); const path = require('path'); // Create an HTTP server based on Express const app = express(); const server = require('http').createServer(app); app.use(express.static(path.join(__dirname, 'public')));
Определение вызываемой
/negotiate
конечной точки. Клиент записи сначала попадает в эту конечную точку. Эта конечная точка возвращает HTTP-ответ. Ответ содержит конечную точку, которую клиент должен использовать для установления постоянного подключения. Он также возвращаетroom
значение, которому назначен клиент./*server.js*/ app.get('/negotiate', async (req, res) => { res.json({ url: endpoint room_id: Math.random().toString(36).slice(2, 7), }); }); // Make the Socket.IO server listen on port 3000 io.httpServer.listen(3000, () => { console.log('Visit http://localhost:%d', 3000); });
Создание веб-pubSub для сервера Socket.IO
Импортируйте web PubSub для пакета SDK для Socket.IO и определите параметры:
Необработанные строка подключения отображаются в этой статье только для демонстрационных целей. В рабочих средах всегда защищать ключи доступа. Используйте Azure Key Vault для безопасного управления ключами и защиты подключения.
WebPubSubServiceClient
/*server.js*/ const { useAzureSocketIO } = require("@azure/web-pubsub-socket.io"); const wpsOptions = { hub: "codestream", connectionString: process.argv[2] }
Создайте web PubSub для сервера Socket.IO:
/*server.js*/ const io = require("socket.io")(); useAzureSocketIO(io, wpsOptions);
Два шага немного отличаются от того, как обычно создается сервер Socket.IO, как описано в этой Socket.IO документации. С помощью этих двух шагов код на стороне сервера может выгрузить постоянные подключения к службе Azure. С помощью службы Azure сервер приложений выступает только в качестве упрощенного HTTP-сервера.
Реализация бизнес-логики
Теперь, когда вы создали сервер Socket.IO, размещенный в Web PubSub, вы можете определить, как клиенты и сервер взаимодействуют с помощью API Socket.IO. Этот процесс называется реализацией бизнес-логики.
После подключения клиента сервер приложений сообщает клиенту, что он вошел в систему, отправив пользовательское событие с именем
login
./*server.js*/ io.on('connection', socket => { socket.emit("login"); });
Каждый клиент выдает два события, на которые сервер может реагировать:
joinRoom
иsendToRoom
. После того как сервер получаетroom_id
значение, которое клиент хочет присоединить, вы используетеsocket.join
API Socket.IO для присоединения целевого клиента к указанной комнате./*server.js*/ socket.on('joinRoom', async (message) => { const room_id = message["room_id"]; await socket.join(room_id); });
После присоединения клиента сервер сообщает клиенту о успешном результате, отправив
message
событие. Когда клиент получаетmessage
событие с типомackJoinRoom
, клиент может попросить сервера отправить последнее состояние редактора./*server.js*/ socket.on('joinRoom', async (message) => { // ... socket.emit("message", { type: "ackJoinRoom", success: true }) });
/*client.js*/ socket.on("message", (message) => { let data = message; if (data.type === 'ackJoinRoom' && data.success) { sendToRoom(socket, `${room_id}-control`, { data: 'sync'}); } // ... });
Когда клиент отправляет
sendToRoom
событие на сервер, сервер передает изменения в состояние редактора кода в указанную комнату. Теперь все клиенты в комнате могут получать последнее обновление.socket.on('sendToRoom', (message) => { const room_id = message["room_id"] const data = message["data"] socket.broadcast.to(room_id).emit("message", { type: "editorMessage", data: data }); });
Написание клиентского кода приложения
Теперь, когда серверные процедуры завершены, вы можете работать на стороне клиента.
Начальная настройка
Необходимо создать клиент Socket.IO для взаимодействия с сервером. Вопрос заключается в том, с каким сервером клиент должен установить постоянное подключение. Так как вы используете Web PubSub для Socket.IO, сервер — это служба Azure. Помните, что вы определили маршрут /negotiate для обслуживания клиентов конечной точки в Web PubSub для Socket.IO.
/*client.js*/
async function initialize(url) {
let data = await fetch(url).json()
updateStreamId(data.room_id);
let editor = createEditor(...); // Create an editor component
var socket = io(data.url, {
path: "/clients/socketio/hubs/codestream",
});
return [socket, editor, data.room_id];
}
Функция initialize(url)
упорядочивает несколько операций установки вместе:
- Извлекает конечную точку в службу Azure с HTTP-сервера.
- Создание экземпляра редактора Монако
- Устанавливает постоянное подключение к Web PubSub для Socket.IO
Клиент записи
Как упоминалось ранее, у вас есть две роли пользователей на стороне клиента: средство записи и средства просмотра. Все, что типы записи передаются на экран средства просмотра.
Получите конечную точку в Web PubSub для Socket.IO и
room_id
значения:/*client.js*/ let [socket, editor, room_id] = await initialize('/negotiate');
Когда клиент записи подключен к серверу, сервер отправляет
login
событие записи. Средство записи может отвечать, запрашивая сервер присоединиться к указанной комнате. Каждые 200 миллисекунда клиент записи отправляет последнее состояние редактора в комнату. Функция с именемflush
упорядочивает логику отправки./*client.js*/ socket.on("login", () => { updateStatus('Connected'); joinRoom(socket, `${room_id}`); setInterval(() => flush(), 200); // Update editor content // ... });
Если модуль записи не вносит никаких изменений,
flush()
ничего не делает и просто возвращается. В противном случае изменения состояния редактора отправляются в комнату./*client.js*/ function flush() { // No changes from editor need to be flushed if (changes.length === 0) return; // Broadcast the changes made to editor content sendToRoom(socket, room_id, { type: 'delta', changes: changes version: version++, }); changes = []; content = editor.getValue(); }
При подключении нового клиента средства просмотра средство просмотра должно получить последнее полное состояние редактора. Для этого сообщение, содержащее
sync
данные, отправляется клиенту записи. Сообщение просит клиента записи отправить полное состояние редактора./*client.js*/ socket.on("message", (message) => { let data = message.data; if (data.data === 'sync') { // Broadcast the full content of the editor to the room sendToRoom(socket, room_id, { type: 'full', content: content version: version, }); } });
Клиент средства просмотра
Как и клиент записи, клиент средства просмотра создает свой Socket.IO клиент через
initialize()
. Когда клиент средства просмотра подключен и получаетlogin
событие от сервера, он просит сервер присоединиться к указанной комнате. Запросroom_id
указывает комнату./*client.js*/ let [socket, editor] = await initialize(`/register?room_id=${room_id}`) socket.on("login", () => { updateStatus('Connected'); joinRoom(socket, `${room_id}`); });
Когда клиент средства просмотра получает
message
событие от сервера и типackJoinRoom
данных, клиент средства просмотра запрашивает клиент записи в комнате, чтобы отправить полное состояние редактора./*client.js*/ socket.on("message", (message) => { let data = message; // Ensures the viewer client is connected if (data.type === 'ackJoinRoom' && data.success) { sendToRoom(socket, `${id}`, { data: 'sync'}); } else //... });
Если тип данных задан
editorMessage
, клиент средства просмотра обновляет редактор в соответствии с фактическим содержимым./*client.js*/ socket.on("message", (message) => { ... else if (data.type === 'editorMessage') { switch (data.data.type) { case 'delta': // ... Let editor component update its status break; case 'full': // ... Let editor component update its status break; } } });
Реализуйте
joinRoom()
иsendToRoom()
используя API Socket.IO:/*client.js*/ function joinRoom(socket, room_id) { socket.emit("joinRoom", { room_id: room_id, }); } function sendToRoom(socket, room_id, data) { socket.emit("sendToRoom", { room_id: room_id, data: data }); }
Выполнение приложения
Поиск репозитория
В предыдущих разделах описана основная логика, связанная с синхронизацией состояния редактора между средствами просмотра и средством записи. Полный код можно найти в репозитории примеров.
Клонирование репозитория
Вы можете клонировать репозиторий и запустить npm install
для установки зависимостей проекта.
Запуск сервера
node server.js <web-pubsub-connection-string>
Это строка подключения, полученные на предыдущем шаге.
Воспроизведение с редактором кода в режиме реального времени
Откройте вкладку браузера. Откройте http://localhost:3000
другую вкладку с URL-адресом, отображаемым на первой веб-странице.
При написании кода на первой вкладке на другой вкладке вы увидите, что ввод в режиме реального времени отражается на другой вкладке. Web PubSub для Socket.IO упрощает передачу сообщений в облаке. Сервер express
обслуживает только статический index.html
файл и конечную точку /negotiate
.