Vytvoření aplikace pro streamování kódu v reálném čase pomocí Socket.IO a jeho hostování v Azure
Vytváření prostředí v reálném čase, jako je funkce spoluvytování v Microsoft Wordu , může být náročné.
Prostřednictvím snadno použitelných rozhraní API se Socket.IO osvědčila jako knihovna pro komunikaci mezi klienty a serverem v reálném čase. Socket.IO ale uživatelé často hlásí potíže se škálováním připojení Socket.IO. Díky službě Web PubSub pro Socket.IO už se vývojáři nemusí starat o správu trvalých připojení.
Důležité
Nezpracované připojovací řetězec se v tomto článku zobrazují jenom pro demonstrační účely.
Připojovací řetězec obsahuje informace o autorizaci vyžadované pro vaši aplikaci pro přístup ke službě Azure Web PubSub. Přístupový klíč uvnitř připojovací řetězec je podobný kořenovému heslu pro vaši službu. V produkčních prostředích vždy chraňte přístupové klíče. Pomocí služby Azure Key Vault můžete bezpečně spravovat a obměňovat klíče a zabezpečit připojení WebPubSubServiceClient
.
Vyhněte se distribuci přístupových klíčů ostatním uživatelům, jejich pevnému kódování nebo jejich uložení kdekoli ve formátu prostého textu, který je přístupný ostatním uživatelům. Otočte klíče, pokud se domníváte, že mohly být ohroženy.
Přehled
Tento článek ukazuje, jak vytvořit aplikaci, která umožňuje coderu streamovat aktivity kódování cílové skupině. Tuto aplikaci sestavíte pomocí:
- Monaco Editor, editor kódu, který využívá Visual Studio Code.
- Express, webová architektura Node.js.
- Rozhraní API, která knihovna Socket.IO poskytuje pro komunikaci v reálném čase.
- Hostování Socket.IO připojení, která pro Socket.IO používají web PubSub.
Dokončená aplikace
Hotová aplikace umožňuje uživateli editoru kódu sdílet webový odkaz, přes který můžou uživatelé sledovat psaní.
Tento článek definuje dvě role uživatelů a to, co můžou dělat v editoru, aby byly postupy zaměřené a přehledné přibližně za 15 minut:
- Autor, který může psát v online editoru a obsah se streamuje
- Čtenáři, kteří dostávají obsah napsaný v reálném čase a nemůžou obsah upravovat
Architektura
Položka | Účel | Zaměstnanecké výhody |
---|---|---|
knihovna Socket.IO | Poskytuje mechanismus výměny dat s nízkou latencí mezi back-endovou aplikací a klienty. | Snadno použitelná rozhraní API, která pokrývají většinu scénářů komunikace v reálném čase |
Web PubSub pro Socket.IO | Hostuje trvalá připojení typu WebSocket nebo poll-based s klienty Socket.IO. | Podpora 100 000 souběžných připojení; Zjednodušená architektura aplikací |
Požadavky
Pokud chcete postupovat podle všech kroků v tomto článku, potřebujete:
- Účet Azure. Pokud ještě nemáte předplatné Azure, vytvořte si bezplatný účet Azure, než začnete.
- Azure CLI (verze 2.29.0 nebo novější) nebo Azure Cloud Shell ke správě prostředků Azure.
- Základní znalost rozhraní API Socket.IO
Vytvoření webového pubSub pro prostředek Socket.IO
K vytvoření prostředku použijte Azure CLI:
az webpubsub create -n <resource-name> \
-l <resource-location> \
-g <resource-group> \
--kind SocketIO \
--sku Free_F1
Získání připojovací řetězec
Připojovací řetězec umožňuje připojení k web pubSub pro Socket.IO.
Spusťte následující příkazy. Nechte vrácenou připojovací řetězec někde, protože ji budete potřebovat při spuštění aplikace později v tomto článku.
az webpubsub key show -n <resource-name> \
-g <resource-group> \
--query primaryKey \
-o tsv
Napsání kódu na straně serveru aplikace
Začněte psát kód aplikace tím, že pracujete na straně serveru.
Vytvoření serveru HTTP
Vytvoření projektu Node.js:
mkdir codestream cd codestream npm init
Nainstalujte sadu SDK serveru a Express:
npm install @azure/web-pubsub-socket.io npm install express
Naimportujte požadované balíčky a vytvořte server HTTP pro obsluhu statických souborů:
/*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')));
Definujte koncový bod s názvem
/negotiate
. Klient zapisovače nejprve dosáhne tohoto koncového bodu. Tento koncový bod vrátí odpověď HTTP. Odpověď obsahuje koncový bod, který by měl klient použít k navázání trvalého připojení. Vrátí takéroom
hodnotu, ke které je klient přiřazen./*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); });
Vytvoření webového pubSub pro server Socket.IO
Naimportujte web PubSub pro sadu Socket.IO SDK a definujte možnosti:
Nezpracované připojovací řetězec se v tomto článku zobrazují jenom pro demonstrační účely. V produkčních prostředích vždy chraňte přístupové klíče. Pomocí služby Azure Key Vault můžete bezpečně spravovat a obměňovat klíče a zabezpečit připojení
WebPubSubServiceClient
./*server.js*/ const { useAzureSocketIO } = require("@azure/web-pubsub-socket.io"); const wpsOptions = { hub: "codestream", connectionString: process.argv[2] }
Vytvořte web pubSub pro server Socket.IO:
/*server.js*/ const io = require("socket.io")(); useAzureSocketIO(io, wpsOptions);
Dva kroky se mírně liší od toho, jak byste normálně vytvořili Socket.IO server, jak je popsáno v této Socket.IO dokumentaci. Pomocí těchto dvou kroků může kód na straně serveru přesměrovat správu trvalých připojení ke službě Azure. S pomocí služby Azure funguje aplikační server jenom jako jednoduchý server HTTP.
Implementace obchodní logiky
Teď, když jste vytvořili server Socket.IO hostovaný webem PubSub, můžete definovat, jak klienti a server komunikují pomocí rozhraní API Socket.IO. Tento proces se nazývá implementace obchodní logiky.
Po připojení klienta aplikační server informuje klienta, že je přihlášený odesláním vlastní události s názvem
login
./*server.js*/ io.on('connection', socket => { socket.emit("login"); });
Každý klient generuje dvě události, na které může server reagovat:
joinRoom
asendToRoom
. Jakmile server získároom_id
hodnotu, ke které se klient chce připojit, použijetesocket.join
rozhraní API Socket.IO k připojení cílového klienta k zadané místnosti./*server.js*/ socket.on('joinRoom', async (message) => { const room_id = message["room_id"]; await socket.join(room_id); });
Po připojení klienta server informuje klienta o úspěšném výsledku odesláním
message
události. Když klient obdržímessage
událost s typemackJoinRoom
, klient může požádat server, aby odeslal nejnovější stav editoru./*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'}); } // ... });
Když klient odešle
sendToRoom
na server událost, server odešle změny do stavu editoru kódu do zadané místnosti. Všichni klienti v místnosti teď můžou dostávat nejnovější aktualizaci.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 }); });
Napsání kódu na straně klienta aplikace
Po dokončení postupů na straně serveru můžete pracovat na straně klienta.
Počáteční nastavení
Pro komunikaci se serverem je potřeba vytvořit klienta Socket.IO. Otázkou je, se kterým serverem by měl klient navázat trvalé připojení. Vzhledem k tomu, že pro Socket.IO používáte Web PubSub, je server službou Azure. Vzpomeňte si, že jste definovali trasu /negotiate , která klientům obsluhuje koncový bod do webového pubSub pro 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];
}
Funkce initialize(url)
organizuje několik operací nastavení dohromady:
- Načtení koncového bodu do služby Azure ze serveru HTTP
- Vytvoří instanci Editoru Monaka.
- Vytvoří trvalé připojení s web pubSub pro Socket.IO
Klient pro zápis
Jak už bylo zmíněno dříve, máte na straně klienta dvě role uživatele: zapisovač a prohlížeč. Cokoli, co autoři zapisují, se streamuje na obrazovku prohlížeče.
Získejte koncový bod do web pubSub pro Socket.IO a
room_id
hodnotu:/*client.js*/ let [socket, editor, room_id] = await initialize('/negotiate');
Když je klient zápisu připojen k serveru, server odešle
login
událost zápisu. Zapisovač může odpovědět tak, že požádá server, aby se připojil k zadané místnosti. Každých 200 milisekund klient zapisovače odešle do místnosti nejnovější stav editoru. Funkce s názvemflush
uspořádá odesílající logiku./*client.js*/ socket.on("login", () => { updateStatus('Connected'); joinRoom(socket, `${room_id}`); setInterval(() => flush(), 200); // Update editor content // ... });
Pokud zapisovač neprovede žádné úpravy,
flush()
nic nedělá a jednoduše se vrátí. V opačném případě se změny stavu editoru odešlou do místnosti./*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(); }
Když je připojen nový klient prohlížeče, musí prohlížeč získat nejnovější úplný stav editoru. K dosažení tohoto cíle se klientovi zapisovače odešle zpráva obsahující
sync
data. Zpráva požádá klienta zapisovače, aby odeslal úplný stav editoru./*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, }); } });
Klient prohlížeče
Stejně jako klient pro zápis vytvoří klient prohlížeče svůj Socket.IO klienta prostřednictvím
initialize()
. Když je klient prohlížeče připojený a přijmelogin
událost ze serveru, požádá server, aby se připojil k zadané místnosti.room_id
Dotaz určuje místnost./*client.js*/ let [socket, editor] = await initialize(`/register?room_id=${room_id}`) socket.on("login", () => { updateStatus('Connected'); joinRoom(socket, `${room_id}`); });
Když klient prohlížeče obdrží
message
událost ze serveru a datový typ jeackJoinRoom
, klient prohlížeče požádá klienta zapisovače v místnosti, aby odeslal úplný stav editoru./*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 //... });
Pokud je
editorMessage
datový typ , klient prohlížeče aktualizuje editor podle jeho skutečného obsahu./*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; } } });
Implementujte
joinRoom()
asendToRoom()
pomocí rozhraní 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 }); }
Spuštění aplikace
Vyhledání úložiště
Předchozí části zahrnovaly základní logiku související se synchronizací stavu editoru mezi diváky a zapisovačem. Kompletní kód najdete v úložišti příkladů.
Klonování úložiště
Úložiště můžete naklonovat a spustit npm install
a nainstalovat závislosti projektu.
Spuštění serveru
node server.js <web-pubsub-connection-string>
Toto je připojovací řetězec, které jste obdrželi v předchozím kroku.
Přehrávání v editoru kódu v reálném čase
Otevřete http://localhost:3000
na kartě prohlížeče. Otevřete jinou kartu s adresou URL zobrazenou na první webové stránce.
Pokud napíšete kód na první kartě, měli byste vidět, že se psaní projeví v reálném čase na druhé kartě. Web PubSub pro Socket.IO usnadňuje předávání zpráv v cloudu. Váš express
server obsluhuje pouze statický index.html
soubor a /negotiate
koncový bod.