Valós idejű kódstreamelési alkalmazás létrehozása Socket.IO használatával és az Azure-ban való üzemeltetésével
A Microsoft Word együttes létrehozási funkciójával hasonló valós idejű élmény létrehozása kihívást jelenthet.
A könnyen használható API-kkal Socket.IO az ügyfelek és a kiszolgálók közötti valós idejű kommunikáció kódtáraként bizonyult. Azonban Socket.IO felhasználók gyakran jelentenek nehézséget a Socket.IO kapcsolatainak skálázásával kapcsolatban. A Web PubSub for Socket.IO esetében a fejlesztőknek már nem kell aggódniuk az állandó kapcsolatok kezelése miatt.
Áttekintés
Ez a cikk bemutatja, hogyan hozhat létre olyan alkalmazást, amely lehetővé teszi a kódoló számára, hogy kódolási tevékenységeket streameljen a közönségnek. Ezt az alkalmazást a következő használatával hozhatja létre:
- Monaco Editor, a Visual Studio Code-ot irányító kódszerkesztő.
- Express, egy Node.js webes keretrendszer.
- A Socket.IO kódtár által biztosított API-k valós idejű kommunikációt biztosítanak.
- Gazdagép Socket.IO kapcsolatok, amelyek a Web PubSub-t használják Socket.IO.
A kész alkalmazás
A kész alkalmazás lehetővé teszi a kódszerkesztő felhasználójának, hogy megossza egy webes hivatkozást, amelyen keresztül a felhasználók megnézhetik a gépelést.
Az eljárások körülbelül 15 perc alatt történő összpontosítása és emészthetősége érdekében ez a cikk két felhasználói szerepkört és a szerkesztőben elvégezhető műveleteket határozza meg:
- Egy író, aki be tud gépelni az online szerkesztőbe, és a tartalom streamelve van
- Azok a megtekintők, akik valós idejű, az író által beírt tartalmat kapnak, és nem tudják szerkeszteni a tartalmat
Architektúra
Cikk | Purpose | Benefits |
---|---|---|
Socket.IO könyvtár | Alacsony késésű, kétirányú adatcsere mechanizmust biztosít a háttéralkalmazás és az ügyfelek között | Könnyen használható API-k, amelyek a legtöbb valós idejű kommunikációs forgatókönyvet lefedik |
Web PubSub for Socket.IO | WebSocket- vagy lekérdezésalapú állandó kapcsolatokat üzemeltet Socket.IO ügyfelekkel | 100 000 egyidejű kapcsolat támogatása; egyszerűsített alkalmazásarchitektúra |
Előfeltételek
A cikk összes lépésének követéséhez a következőkre van szüksége:
- Egy Azure-fiók. Ha nem rendelkezik Azure-előfizetéssel, a kezdés előtt hozzon létre egy ingyenes Azure-fiókot .
- Az Azure CLI (2.29.0-s vagy újabb verzió) vagy az Azure Cloud Shell az Azure-erőforrások kezeléséhez.
- A Socket.IO API-k alapszintű ismerete.
Web PubSub létrehozása Socket.IO erőforráshoz
Az erőforrás létrehozásához használja az Azure CLI-t:
az webpubsub create -n <resource-name> \
-l <resource-location> \
-g <resource-group> \
--kind SocketIO \
--sku Free_F1
Kapcsolati sztring lekérése
A kapcsolati sztring lehetővé teszi a Web PubSub-hez való kapcsolódást Socket.IO.
Futtassa az alábbi parancsokat. Tartsa valahol a visszaadott kapcsolati sztring, mert szüksége lesz rá, amikor a cikk későbbi részében futtatja az alkalmazást.
az webpubsub key show -n <resource-name> \
-g <resource-group> \
--query primaryKey \
-o tsv
Az alkalmazás kiszolgálóoldali kódjának írása
Kezdje el írni az alkalmazás kódját a kiszolgáló oldalán.
HTTP-kiszolgáló létrehozása
Node.js-projekt létrehozása:
mkdir codestream cd codestream npm init
Telepítse a kiszolgálóIDK-t és az Expresst:
npm install @azure/web-pubsub-socket.io npm install express
Importálja a szükséges csomagokat, és hozzon létre egy HTTP-kiszolgálót a statikus fájlok kiszolgálásához:
/*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')));
Adjon meg egy .-nek nevezett végpontot
/negotiate
. Először egy íróügyfél éri el ezt a végpontot. Ez a végpont HTTP-választ ad vissza. A válasz tartalmaz egy végpontot, amelyet az ügyfélnek egy állandó kapcsolat létrehozásához kell használnia. Azt az értéket is visszaadjaroom
, amelyhez az ügyfél hozzá van rendelve./*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); });
A Web PubSub létrehozása Socket.IO kiszolgálóhoz
Importálja a Web PubSubot Socket.IO SDK-hoz, és adja meg a beállításokat:
/*server.js*/ const { useAzureSocketIO } = require("@azure/web-pubsub-socket.io"); const wpsOptions = { hub: "codestream", connectionString: process.argv[2] }
Web PubSub létrehozása Socket.IO kiszolgálóhoz:
/*server.js*/ const io = require("socket.io")(); useAzureSocketIO(io, wpsOptions);
A két lépés kissé eltér a Socket.IO-kiszolgáló létrehozásának módjától, ahogyan azt ebben a Socket.IO dokumentációban ismertetjük. Ezzel a két lépéssel a kiszolgálóoldali kód ki tudja kapcsolni egy Azure-szolgáltatás állandó kapcsolatainak kezelését. Egy Azure-szolgáltatás segítségével az alkalmazáskiszolgáló csak egy egyszerű HTTP-kiszolgálóként működik.
Üzleti logika megvalósítása
Most, hogy létrehozott egy Socket.IO-kiszolgálót, amelyet a Web PubSub üzemeltet, meghatározhatja, hogyan kommunikálnak az ügyfelek és a kiszolgáló a Socket.IO API-jaival. Ezt a folyamatot üzleti logika implementálásának nevezzük.
Az ügyfél csatlakoztatása után az alkalmazáskiszolgáló egy egyéni, névvel ellátott
login
esemény küldésével tájékoztatja az ügyfelet arról, hogy be van jelentkezve./*server.js*/ io.on('connection', socket => { socket.emit("login"); });
Minden ügyfél két eseményt bocsát ki, amelyekre a kiszolgáló válaszolhat:
joinRoom
éssendToRoom
. Miután a kiszolgáló megkapja azt azroom_id
értéket, amelyhez egy ügyfél csatlakozni szeretne, asocket.join
Socket.IO API-jával csatlakozhat a célügyfélhez a megadott helyiséghez./*server.js*/ socket.on('joinRoom', async (message) => { const room_id = message["room_id"]; await socket.join(room_id); });
Az ügyfél csatlakoztatása után a kiszolgáló egy esemény küldésével tájékoztatja az ügyfelet
message
a sikeres eredményről. Amikor az ügyfél egy ilyen típusúackJoinRoom
eseménytmessage
kap, az ügyfél megkérheti a kiszolgálót, hogy küldje el a legújabb szerkesztőállapotot./*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'}); } // ... });
Amikor egy ügyfél eseményt
sendToRoom
küld a kiszolgálónak, a kiszolgáló a kódszerkesztő állapotának módosításait a megadott helyiségbe továbbítja. A helyiség összes ügyfele megkapja a legújabb frissítést.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 }); });
Az alkalmazás ügyféloldali kódjának írása
Most, hogy a kiszolgálóoldali eljárások befejeződnek, az ügyféloldalon is dolgozhat.
Kezdeti beállítás
Létre kell hoznia egy Socket.IO ügyfelet a kiszolgálóval való kommunikációhoz. A kérdés az, hogy melyik kiszolgálóval kell állandó kapcsolatot létesítenie az ügyfélnek. Mivel a Web PubSub-t használja Socket.IO, a kiszolgáló egy Azure-szolgáltatás. Ne feledje, hogy definiált egy /negotiate útvonalat, amely az ügyfelek számára végpontot biztosít a Web PubSub számára 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];
}
A initialize(url)
függvény néhány beállítási műveletet együtt rendszerez:
- Lekéri a végpontot egy Azure-szolgáltatásba a HTTP-kiszolgálóról
- Monaco Editor-példány létrehozása
- Állandó kapcsolatot hoz létre a Web PubSub szolgáltatással a Socket.IO
Íróügyfél
Ahogy korábban említettük, két felhasználói szerepköre van az ügyféloldalon: író és megtekintő. Minden, amit az író típusok streamelnek a megjelenítő képernyőjére.
Kérje le a végpontot a Web PubSubhoz Socket.IO és az
room_id
értékhez:/*client.js*/ let [socket, editor, room_id] = await initialize('/negotiate');
Amikor az íróügyfél csatlakozik a kiszolgálóhoz, a kiszolgáló eseményt
login
küld az írónak. Az író úgy válaszolhat, hogy megkéri a kiszolgálót, hogy csatlakozzon egy adott helyiséghez. Minden 200 ezredmásodpercben az íróügyfél elküldi a legújabb szerkesztői állapotot a szobába. Egy elnevezettflush
függvény rendszerezi a küldési logikát./*client.js*/ socket.on("login", () => { updateStatus('Connected'); joinRoom(socket, `${room_id}`); setInterval(() => flush(), 200); // Update editor content // ... });
Ha egy író nem végez módosításokat, nem tesz semmit,
flush()
és egyszerűen visszatér. Ellenkező esetben a szerkesztő állapotának módosításait a rendszer elküldi a helyiségnek./*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(); }
Ha egy új megtekintő ügyfél csatlakozik, a megtekintőnek a szerkesztő legújabb teljes állapotát kell megkapnia. Ennek eléréséhez a rendszer adatokat tartalmazó
sync
üzenetet küld az íróügyfélnek. Az üzenet arra kéri az íróügyfélt, hogy küldje el a teljes szerkesztői állapotot./*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, }); } });
Megtekintő ügyfél
Az íróügyfélhöz hasonlóan a megtekintő ügyfél is létrehozza a Socket.IO-ügyfelet.
initialize()
Amikor a megtekintő ügyfél csatlakoztatva van, és eseménytlogin
kap a kiszolgálótól, felkéri a kiszolgálót, hogy csatlakozzon a megadott helyiséghez. A lekérdezésroom_id
megadja a helyiséget./*client.js*/ let [socket, editor] = await initialize(`/register?room_id=${room_id}`) socket.on("login", () => { updateStatus('Connected'); joinRoom(socket, `${room_id}`); });
Amikor egy megtekintő ügyfél eseményt
message
kap a kiszolgálótól, és az adattípus azackJoinRoom
, a megtekintő ügyfél megkéri a szobában lévő íróügyfélt, hogy küldje el a teljes szerkesztőállapotot./*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 //... });
Ha az adattípus az
editorMessage
, a megtekintő ügyfél a tényleges tartalomnak megfelelően frissíti a szerkesztőt ./*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; } } });
Implementálja
joinRoom()
éssendToRoom()
használja a Socket.IO API-jait:/*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 }); }
Az alkalmazás futtatása
Az adattár megkeresése
Az előző szakaszok a szerkesztő állapotának a megtekintők és az író közötti szinkronizálásával kapcsolatos alapvető logikát fedik le. A teljes kódot a példák adattárában találja.
Az adattár klónozása
Klónozhatja az adattárat, és futtathatja npm install
a projektfüggőségek telepítéséhez.
A kiszolgáló indítása
node server.js <web-pubsub-connection-string>
Ez az a kapcsolati sztring, amelyet egy korábbi lépésben kapott.
Lejátszás a valós idejű kódszerkesztővel
Megnyitás http://localhost:3000
böngészőlapon. Nyisson meg egy másik lapot az első weblapon megjelenő URL-címmel.
Ha az első lapon kódot ír, akkor a gépelés valós időben jelenik meg a másik lapon. A Web PubSub for Socket.IO megkönnyíti az üzenetek felhőben való továbbítását. A express
kiszolgáló csak a statikus index.html
fájlt és a végpontot /negotiate
szolgálja ki.