Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
La creazione di un'esperienza in tempo reale come la funzionalità di creazione condivisa in Microsoft Word può risultare complessa.
Grazie alle API facili da usare, Socket.IO si è dimostrata come una libreria per la comunicazione in tempo reale tra client e server. Tuttavia, gli utenti di Socket.IO segnalano spesso difficoltà nel gestire la scalabilità delle connessioni di Socket.IO. Con Web PubSub per Socket.IO, gli sviluppatori non devono più preoccuparsi della gestione delle connessioni persistenti.
Importante
Le stringa di connessione non elaborate vengono visualizzate in questo articolo solo a scopo dimostrativo.
Una stringa di connessione include le informazioni di autorizzazione di cui la tua applicazione ha bisogno per accedere al servizio Azure Web PubSub. La chiave di accesso nella stringa di connessione agisce come una password root per il tuo servizio. Negli ambienti di produzione proteggere sempre le chiavi di accesso. Usare Azure Key Vault per gestire e ruotare le chiavi in modo sicuro e proteggere la connessione con WebPubSubServiceClient.
Evitare di distribuire le chiavi di accesso ad altri utenti, impostarle come hardcoded o salvarle in un file di testo normale accessibile ad altri. Ruotare le chiavi se si ritiene che siano state compromesse.
Panoramica
Questo articolo illustra come creare un'app che consente a un coder di trasmettere attività di codifica a un gruppo di destinatari. Per compilare questa applicazione, usare:
- Editor Monaco, l'editor di codice che supporta Visual Studio Code.
- Express, un framework Web Node.js.
- API fornite dalla libreria di Socket.IO per la comunicazione in tempo reale.
- Ospita connessioni Socket.IO che usano Web PubSub per Socket.IO.
L'app completata
L'app completata consente all'utente di un editor di codice di condividere un collegamento Web tramite il quale gli utenti possono osservare la digitazione.
Per mantenere incentrate e digeribili le procedure in circa 15 minuti, questo articolo definisce due ruoli utente e le operazioni che possono eseguire nell'editor:
- Writer, che può digitare nell'editor online e il contenuto viene trasmesso in streaming
- Spettatori, che ricevono in tempo reale i contenuti digitati dal redattore e non possono modificarli
Architettura
| Articolo | Scopo | Vantaggi |
|---|---|---|
| libreria Socket.IO | Fornisce un meccanismo di scambio di dati bidirezionali a bassa latenza tra l'applicazione back-end e i client | API facili da usare che coprono la maggior parte degli scenari di comunicazione in tempo reale |
| Web PubSub per Socket.IO | Ospita connessioni persistenti basate su WebSocket o su polling con client Socket.IO | Supporto per 100.000 connessioni simultanee; architettura dell'applicazione semplificata |
Prerequisiti
Per seguire tutti i passaggi descritti in questo articolo, è necessario:
- Un account Azure. Se non si ha una sottoscrizione di Azure, creare un account Azure gratuito prima di iniziare.
- Interfaccia della riga di comando di Azure (versione 2.29.0 o successiva) o Azure Cloud Shell per gestire le risorse di Azure.
- Conoscenza di base delle API di Socket.IO.
Creare una risorsa Web PubSub per Socket.IO
Usare l'interfaccia della riga di comando di Azure per creare la risorsa:
az webpubsub create -n <resource-name> \
-l <resource-location> \
-g <resource-group> \
--kind SocketIO \
--sku Free_F1
Ottenere una stringa di connessione
Un stringa di connessione consente di connettersi con Web PubSub per Socket.IO.
Eseguire i comandi seguenti. Conserva da qualche parte la stringa di connessione restituita, perché ti servirà quando eseguirai l'applicazione più avanti in questo articolo.
az webpubsub key show -n <resource-name> \
-g <resource-group> \
--query primaryKey \
-o tsv
Scrivere il codice lato server dell'applicazione
Iniziare a scrivere il codice dell'applicazione lavorando sul lato server.
Creare un server HTTP
Creare un progetto Node.js:
mkdir codestream cd codestream npm initInstallare l'SDK del server ed Express:
npm install @azure/web-pubsub-socket.io npm install expressImportare i pacchetti necessari e creare un server HTTP per gestire i file statici:
/*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')));Definire un endpoint denominato
/negotiate. Un client writer raggiunge prima questo endpoint. Questo endpoint restituisce una risposta HTTP. La risposta contiene un endpoint che il client deve usare per stabilire una connessione permanente. Restituisce anche unroomvalore a cui è assegnato il client./*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); });
Crea il server Web PubSub for Socket.IO
Importare Web PubSub per Socket.IO SDK e definire le opzioni:
Le stringa di connessione non elaborate vengono visualizzate in questo articolo solo a scopo dimostrativo. Negli ambienti di produzione proteggere sempre le chiavi di accesso. Usare Azure Key Vault per gestire e ruotare le chiavi in modo sicuro e proteggere la connessione con
WebPubSubServiceClient./*server.js*/ const { useAzureSocketIO } = require("@azure/web-pubsub-socket.io"); const wpsOptions = { hub: "codestream", connectionString: process.argv[2] }Creare un Web PubSub per Socket.IO server:
/*server.js*/ const io = require("socket.io")(); useAzureSocketIO(io, wpsOptions);
I due passaggi sono leggermente diversi da come si crea normalmente un server Socket.IO, come descritto in questa documentazione Socket.IO. Con questi due passaggi, il codice lato server può eseguire l'offload della gestione delle connessioni permanenti a un servizio di Azure. Con l'aiuto di un servizio di Azure, il server applicazioni funge solo da server HTTP leggero.
Implementare la logica di business
Ora che è stato creato un server Socket.IO ospitato da Web PubSub, è possibile definire il modo in cui i client e il server comunicano usando le API di Socket.IO. Questo processo viene chiamato implementazione della logica di business.
Dopo la connessione di un client, il server applicazioni indica al client che è connesso inviando un evento personalizzato denominato
login./*server.js*/ io.on('connection', socket => { socket.emit("login"); });Ogni client genera due eventi a cui il server può rispondere:
joinRoomesendToRoom. Dopo che il server riceve il valoreroom_iddella stanza a cui un client vuole unirsi, si usasocket.joindell'API di Socket.IO per far entrare il client di destinazione nella stanza specificata./*server.js*/ socket.on('joinRoom', async (message) => { const room_id = message["room_id"]; await socket.join(room_id); });Dopo che un client è stato aggiunto, il server informa il client del risultato riuscito inviando un
messageevento. Quando il client riceve unmessageevento con un tipo diackJoinRoom, il client può chiedere al server di inviare lo stato dell'editor più recente./*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'}); } // ... });Quando un client invia un
sendToRoomevento al server, il server trasmette le modifiche allo stato dell'editor di codice nella sala specificata. Tutti i client nella sala possono ora ricevere l'aggiornamento più recente.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 }); });
Scrivere il codice lato client dell'applicazione
Ora che le procedure sul lato server sono state completate, è possibile lavorare sul lato client.
Configurazione iniziale
È necessario creare un client Socket.IO per comunicare con il server. La domanda è il server con cui il client deve stabilire una connessione permanente. Poiché si usa Web PubSub per Socket.IO, il server è un servizio di Azure. Ricorda che hai definito una route /negotiate per fornire ai client un endpoint per Web PubSub per 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];
}
La initialize(url) funzione organizza alcune operazioni di configurazione insieme:
- Recupera l'endpoint di un servizio Azure dal tuo server HTTP
- Crea un'istanza di Monaco Editor
- Stabilisce una connessione permanente con Web PubSub per Socket.IO
Client di scrittura
Come accennato in precedenza, si hanno due ruoli utente sul lato client: writer e visualizzatore. Tutto ciò che l'utente digita viene trasmesso sullo schermo del visualizzatore.
Recuperare l'endpoint di Web PubSub per Socket.IO e il valore
room_id:/*client.js*/ let [socket, editor, room_id] = await initialize('/negotiate');Quando il client writer è connesso al server, il server invia un
loginevento al writer. Il writer può rispondere chiedendo al server di aggiungersi a una sala specificata. Ogni 200 millisecondi, il client di scrittura invia alla stanza lo stato più recente dell'editor. Una funzione denominataflushorganizza la logica di invio./*client.js*/ socket.on("login", () => { updateStatus('Connected'); joinRoom(socket, `${room_id}`); setInterval(() => flush(), 200); // Update editor content // ... });Se un writer non apporta modifiche,
flush()non esegue alcuna operazione e restituisce semplicemente. In caso contrario, le modifiche apportate allo stato dell'editor vengono inviate alla sala./*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(); }Quando un nuovo client visualizzatore è connesso, il visualizzatore deve ottenere lo stato completo più recente dell'editor. A tale scopo, viene inviato un messaggio che contiene
syncdati al client writer. Il messaggio chiede al client writer di inviare lo stato completo dell'editor./*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, }); } });
Client visualizzatore
Analogamente al client writer, il client del visualizzatore crea il client Socket.IO tramite
initialize(). Quando il client del visualizzatore è connesso e riceve unloginevento dal server, chiede al server di aggiungersi alla sala specificata. La queryroom_idspecifica la sala./*client.js*/ let [socket, editor] = await initialize(`/register?room_id=${room_id}`) socket.on("login", () => { updateStatus('Connected'); joinRoom(socket, `${room_id}`); });Quando un client di visualizzazione riceve un evento
messagedal server e il tipo di dati èackJoinRoom, il client di visualizzazione chiede al client di scrittura nella stanza di inviare lo stato completo dell'editor./*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 //... });Se il tipo di dati è
editorMessage, il client del visualizzatore aggiorna l'editor in base al contenuto effettivo./*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; } } });Implementare
joinRoom()esendToRoom()usando le API di 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 }); }
Eseguire l'applicazione
Trova il repository
Le sezioni precedenti hanno illustrato la logica di base correlata alla sincronizzazione dello stato dell'editor tra visualizzatori e writer. È possibile trovare il codice completo nel repository di esempi.
Clona il repository
È possibile clonare il repository ed eseguire npm install per installare le dipendenze del progetto.
Avviare il server
node server.js <web-pubsub-connection-string>
Questa è la stringa di connessione ricevuta in un passaggio precedente.
Prova l'editor di codice in tempo reale
Apri http://localhost:3000 in una scheda del browser. Apri un'altra scheda con l'URL visualizzato nella prima pagina web.
Se si scrive codice nella prima scheda, la digitazione dovrebbe essere riflessa in tempo reale nell'altra scheda. Web PubSub per Socket.IO facilita il passaggio del messaggio nel cloud. Il express server serve solo il file statico index.html e l'endpoint /negotiate .