Addomesticare WebRTC con PeerJS: creare un semplice gioco Web P2P
Pubblicato: 2022-03-11WebRTC è una tecnologia che consente la comunicazione in tempo reale tra browser Web. È relativamente nuovo e la definizione API è ancora considerata una bozza. Insieme al fatto che WebRTC non è ancora supportato da tutti i principali browser Web (e tra quelli che lo fanno, alcuni di essi non supportano tutte le funzionalità di questa tecnologia), ciò rende relativamente difficile l'utilizzo di WebRTC per qualsiasi applicazione mission-critical . O almeno così penseresti!
Da quando è stato introdotto per la prima volta da Google nel maggio 2011, WebRTC è stato utilizzato in molte applicazioni Web moderne. Essendo una caratteristica fondamentale di molti browser Web moderni, le applicazioni Web possono sfruttare senza problemi questa tecnologia per offrire un'esperienza utente migliorata in molti modi. Le applicazioni di streaming video o conferenza che non richiedono plug-in del browser ingombranti e possono sfruttare le reti peer-to-peer (P2P) (senza trasmettere tutti i bit di dati attraverso alcuni server) sono solo una parte di tutte le cose straordinarie che può essere ottenuto con WebRTC.
In questo articolo, daremo un'occhiata a come WebRTC può essere utilizzato per creare un semplice gioco Web P2P di Connect Four. Per aggirare i vari spigoli e le differenze di implementazione di WebRTC, utilizzeremo una straordinaria libreria JavaScript: PeerJS.
Dati su WebRTC
Prima di iniziare, è importante capire che WebRTC non riguarda solo la trasmissione di flussi audio e video. Fornisce inoltre supporto per i canali dati P2P. Questi canali sono disponibili in due varianti: affidabili e inaffidabili. Come si può intuire, i canali di dati affidabili garantiscono che i messaggi vengano consegnati e consegnati in ordine, mentre i canali inaffidabili non forniscono tali garanzie.
Inoltre, i canali di dati WebRTC non richiedono una configurazione dell'infrastruttura speciale, a parte ciò che è necessario per una tipica connessione peer WebRTC: un server di segnalazione per coordinare la connessione tra peer, un server STUN per capire l'identità pubblica dei peer e, facoltativamente, un server TURN per instradare messaggi tra peer se non è possibile stabilire una connessione diretta tra peer (ad esempio quando entrambi i peer sono dietro NAT). Se questi acronimi suonano familiari, è perché WebRTC ripropone le tecnologie esistenti ove possibile.
Questo apre le porte a molti più casi d'uso di WebRTC, inclusi, ma non limitati a, giochi multiplayer, consegna di contenuti e condivisione di file. Anche in questo caso, il tutto senza la necessità di alcun server intermedio e quindi con latenze inferiori.
Nel nostro semplice gioco web, utilizzeremo un canale dati tra due browser web per comunicare le mosse dei giocatori avanti e indietro.
Incontra PeerJS
PeerJS prende l'implementazione di WebRTC nel tuo browser e racchiude intorno ad esso un'API semplice, coerente ed elegante. Colma vari buchi nell'implementazione WebRTC dei browser precedenti. Ad esempio, in Chrome 30 o versioni precedenti erano disponibili solo canali dati inaffidabili. PeerJS, se configurato per utilizzare canali di dati affidabili, userebbe uno shim per quei browser meno recenti. Anche se questo non sarebbe performante come l'implementazione nativa di canali affidabili, funzionerebbe comunque.
Con PeerJS, identificare i peer è ancora più semplice. Ogni peer viene identificato utilizzando nient'altro che un ID. Una stringa che il peer può scegliere da sé o farla generare da un server. Sebbene WebRTC prometta la comunicazione peer-to-peer, è comunque necessario un server che funga da broker di connessione e gestisca la segnalazione. PeerJS fornisce un'implementazione open source di questo server broker di connessione PeerJS Server (scritto in Node.js), nel caso in cui non si desideri utilizzare la loro versione ospitata nel cloud (che al momento è gratuita e presenta alcune limitazioni).
Connect Four Goes P2P
Ora che abbiamo una fonte di fiducia per lavorare con WebRTC, ad esempio PeerJS, iniziamo creando una semplice applicazione Node.js/Express.
npm init npm install express --save npm install jade --save npm install peer --save
Lo useremo solo per ospitare PeerJS Server e servire una pagina e risorse front-end. Avremo bisogno di servire solo una singola pagina e questa conterrà due sezioni: un menu principale semplice e una griglia Connect Four 7-by-6.
Server PeerJS
Ospitare il nostro server PeerJS è davvero facile. Il repository ufficiale su GitHub ha anche un pulsante con un clic per distribuire un'istanza di PeerJS Server su Heroku.
Nel nostro caso, vogliamo solo creare un'istanza di ExpressPeerServer nella nostra applicazione Node.js e servirla in "/peerjs":
var express = require('express') var app = express() // … Configure Express, and register necessary route handlers srv = app.listen(process.env.PORT) app.use('/peerjs', require('peer').ExpressPeerServer(srv, { debug: true }))
Cliente PeerJS
Con PeerJS Server attivo e funzionante, si passa al lato client. Come discusso in precedenza, PeerJS identifica i peer con ID univoci. Questi ID possono essere generati automaticamente da PeerServer per ogni peer, oppure possiamo sceglierne uno per ogni peer durante la creazione di un'istanza di oggetti Peer .
var peer = new Peer(id, options)
Qui, l' id può essere omesso del tutto se vogliamo che il server ne generi uno per noi. Nel nostro caso, questo è ciò che vorremo fare. PeerServer assicurerà che gli ID forniti siano univoci. Il secondo argomento, options , è in genere un oggetto contenente la chiave (la chiave API, se si utilizza un PeerServer ospitato nel cloud, o host , port , path , ecc. nel caso si stia ospitando il PeerServer da soli).
var peer = new Peer({ host: location.hostname, port: location.port || (location.protocol === 'https:' ? 443 : 80), path: '/peerjs' })
Per stabilire una connessione tra due peer JS, uno dei peer deve conoscere l'ID dell'altro peer. Per semplificare le cose, nella nostra implementazione di Connect Four su WebRTC, richiederemo al giocatore che avvia il gioco di condividere il suo peer ID con il suo avversario. Con l'ID peer di destinazione noto, una semplice chiamata a peer.connect(destId) è tutto ciò di cui avremo bisogno:

var conn = peer.connect(destId)
Sia l'oggetto Peer che l'oggetto DataConnection restituiti da peer.connect(destId) emettono alcuni eventi davvero utili che vale la pena ascoltare. Ai fini di questo tutorial, siamo particolarmente interessati all'evento 'data' dell'oggetto DataConnection e agli eventi 'error' di entrambi gli oggetti.
Per inviare dati all'altra estremità della connessione, invoca semplicemente conn.send(data) :
conn.send('hello')
Anche se un po' eccessivo per le nostre esigenze qui, PeerJS trasmette i dati tra peer dopo averli codificati in formato BinaryPack. Ciò consente ai peer di comunicare stringhe, numeri, array, oggetti e persino BLOB.
Per ricevere i dati in entrata, ascolta semplicemente l'evento 'data' su conn :
conn.on('data', function(data) { // data === 'hello' })
E questo è praticamente tutto ciò di cui abbiamo bisogno!
Logica di gioco
Al primo giocatore, quello che inizia una partita, viene mostrato il suo peer ID generato da PeerJS che può condividere con il proprio avversario. Una volta che un avversario si unisce al gioco utilizzando l'ID pari del primo giocatore, il primo giocatore può fare una mossa.
Connect Four, essendo un gioco di regole e meccaniche semplici, ha un solo tipo di mossa: ogni giocatore, a sua volta, deve scegliere una colonna e farvi cadere un disco. Ciò significa che tutto ciò che un peer deve comunicare è il numero di colonna in cui il giocatore corrente ha scelto di inserire il suo disco. Trasmetteremo queste informazioni come un array con due elementi: una stringa 'sposta' e un numero - 0- indice basato della colonna da sinistra.
Ogni volta che un giocatore fa clic su una colonna:
if(!turn) { // it is not the current player's turn return } var i // i = chosen column index if(grid[i].length == 6) { // the column doesn't have any more space available return } // track player's move locally grid[i].push(peerId) // end current player's turn turn = false conn.send(['move', i])
Dopo aver inviato i dati di questa mossa all'avversario, aggiorniamo lo stato del gioco in locale. Ciò include determinare se il giocatore attuale ha vinto o se la partita è finita con un pareggio.
All'estremità ricevente di questi dati di spostamento:
if(turn) { // ignore incoming move data when it is the current player's turn return } var i = data[1] if(grid[i].length == 6) { // ignore incoming move data when it is invalid return } // track opponent's move locally grid[i].push(opponent.peerId) // activate current player's turn turn = true
E naturalmente, dopo questo aggiorniamo localmente lo stato del gioco, determiniamo se l'avversario ha vinto o se il gioco è terminato con un pareggio.
Nota come dobbiamo eseguire controlli di integrità sui dati in arrivo. Questo è importante poiché con i giochi basati su WebRTC non abbiamo server intermediari e logica di gioco basata su server che convalida i dati di spostamento.
Per mantenere semplici gli snippet, le righe di codice che aggiornano l'interfaccia utente sono state omesse. Puoi trovare il codice sorgente completo per JavaScript lato client qui.
Collegando tutto
Per combinare il tutto, creiamo una semplice pagina con due sezioni. Al caricamento della pagina viene mostrata la sezione contenente il menu principale, la sezione contenente la griglia di gioco viene tenuta nascosta.
section#menu div.animated.bounceIn div h1 Connect Four br div.no-support() div.alert.alert-warning p Unfortunately, your web browser does not <a href="http://iswebrtcreadyyet.com">support WebRTC</a> div a.btn.btn-primary.btn-lg(href='#start') Start | a.btn.btn-default.btn-lg(href='#join') Join section#game() div div h1 Connect Four br table.table.grid tbody for i in [0, 1, 2, 3, 4, 5] tr for j in [0, 1, 2, 3, 4, 5, 6] td div.slot br div.alert.alert-info p
Rendere belli questi elementi DOM va oltre lo scopo di questo tutorial. Quindi ricorreremo al nostro fidato compagno Bootstrap e faremo uno stile leggero su di esso.
Quando il primo giocatore fa clic sul pulsante "Inizia", viene mostrata la griglia di gioco insieme all'ID peer del giocatore. Il giocatore può quindi condividere questo peer ID con il proprio avversario.
Il secondo giocatore può fare clic, quindi fare clic sul pulsante "Partecipa", inserire l'ID peer del primo giocatore e iniziare il gioco.
Provarlo
Puoi provare questa applicazione di esempio su https://arteegee.herokuapp.com.
Oppure puoi clonare il repository da GitHub, installare le dipendenze NPM e provarlo localmente:
git clone https://github.com/hjr265/arteegee.git cd arteegee npm install PORT=5000 npm start
Una volta che il server è in esecuzione, puoi puntare il tuo browser web su http://localhost:5000, avviare un gioco da una scheda e accedere da un'altra scheda (o anche da un browser web compatibile con WebRTC diverso) utilizzando l'ID peer.
È possibile aprire la console del browser Web per visualizzare alcune informazioni di debug, poiché in questa applicazione di esempio, il client PeerJS è stato configurato per eseguire la registrazione dettagliata.
Ma non funziona per me!
Ci sono due ragioni principali per cui questo gioco potrebbe non funzionare sul tuo computer.
È possibile che tu stia utilizzando un browser Web che non supporta ancora le API WebRTC necessarie. In tal caso, potresti provare un browser diverso, uno che supporti WebRTC e canali dati.
Se stai utilizzando un browser Web moderno con supporto WebRTC, è possibile che tu sia dietro un'infrastruttura di rete che WebRTC non può penetrare. Idealmente questo problema può essere facilmente risolto con un server TURN, ma poiché l'applicazione di esempio non ne sta utilizzando uno, non funzionerà quando sia tu che il tuo avversario siete dietro NAT.
Conclusione
WebRTC è una nuova tecnologia e le sue implementazioni sono piuttosto lontane dall'essere mature. Questi spesso causano alcune sfide uniche per gli sviluppatori. Tuttavia, con la disponibilità di librerie come PeerJS che astraggono ordinatamente le API grezze grezze, la tecnologia sta già diventando abbastanza accessibile.
Spero che questo breve tutorial per la creazione di un gioco basato su PeerJS ti aiuti a iniziare con WebRTC e a creare fantastiche applicazioni Web peer-to-peer in tempo reale.