Erstellen Sie sofort Multiplayer-Webanwendungen, kein Server erforderlich
DIE DEMO AUSPROBIEREN ?
trystero verwaltet ein geheimes Kuriernetzwerk, das es den Benutzern Ihrer Anwendung ermöglicht, direkt miteinander zu kommunizieren, verschlüsselt und ohne einen Server-Mittelsmann.
Das Netz ist voll von offenen, dezentralen Kommunikationskanälen: Torrent-Tracker, IoT-Gerätebroker, Boutique-Dateiprotokolle und soziale Nischennetzwerke.
trystero greift auf diese Netzwerke zurück, um ohne Ihr Zutun automatisch sichere, private P2P-Verbindungen zwischen den Benutzern Ihrer App herzustellen.
Peers können sich über verbinden? BitTorrent, ? Nostr, ? MQTT, ⚡️ Supabase, Firebase oder ? IPFS – alle verwenden dieselbe API.
trystero ermöglicht nicht nur das automatische Peer-Matching, sondern bietet auch einige nette Abstraktionen zusätzlich zu WebRTC:
Hier können Sie sehen, was die Leute mit trystero bauen.
Wenn Sie trystero einfach nur ausprobieren möchten, können Sie diese Erklärung überspringen und direkt mit der Verwendung beginnen.
Um eine direkte Peer-to-Peer-Verbindung mit WebRTC herzustellen, ist ein Signalisierungskanal zum Austausch von Peer-Informationen (SDP) erforderlich. Normalerweise beinhaltet dies den Betrieb eines eigenen Matchmaking-Servers, aber trystero abstrahiert dies für Sie und bietet mehrere „serverlose“ Strategien zum Verbinden von Peers (derzeit BitTorrent, Nostr, MQTT, Supabase, Firebase und IPFS).
Der wichtige Punkt, den Sie sich merken sollten, ist dieser:
Über die Peer-Erkennung hinaus berühren die Daten Ihrer App niemals das Strategiemedium und werden direkt Peer-to-Peer und Ende-zu-Ende-verschlüsselt zwischen Benutzern gesendet.
?
Hier können Sie Strategien vergleichen.
Sie können mit npm ( npm i trystero
) installieren und wie folgt importieren:
import { joinRoom } from ' trystero '
Oder bevorzugen Sie vielleicht ein einfaches Skript-Tag? Laden Sie eine vorgefertigte JS-Datei aus der neuesten Version herunter und importieren Sie sie lokal:
< script type =" module " >
import { joinRoom } from './ trystero -torrent.min.js'
</ script >
Standardmäßig wird die Nostr-Strategie verwendet. Um ein anderes zu verwenden, importieren Sie es einfach wie folgt tief (Ihr Bundler sollte nur relevanten Code einschließen):
import { joinRoom } from ' trystero /mqtt' // ( trystero -mqtt.min.js with a local file)
// or
import { joinRoom } from ' trystero /torrent' // ( trystero -torrent.min.js)
// or
import { joinRoom } from ' trystero /supabase' // ( trystero -supabase.min.js)
// or
import { joinRoom } from ' trystero /firebase' // ( trystero -firebase.min.js)
// or
import { joinRoom } from ' trystero /ipfs' // ( trystero -ipfs.min.js)
Als nächstes verbinden Sie den Benutzer mit einer ID mit einem Raum:
const config = { appId : 'san_narciso_3d' }
const room = joinRoom ( config , 'yoyodyne' )
Das erste Argument ist ein Konfigurationsobjekt, das eine appId
erfordert. Dies sollte eine völlig eindeutige Kennung für Ihre App sein¹. Das zweite Argument ist die Raum-ID.
Warum Zimmer? Browser können nur eine begrenzte Anzahl von WebRTC-Verbindungen gleichzeitig verarbeiten. Daher wird empfohlen, Ihre App so zu gestalten, dass Benutzer in Gruppen (oder Räume, Namespaces oder Kanäle ... wie auch immer Sie sie nennen möchten) unterteilt sind.
¹ Bei Verwendung von Firebase sollte appId
Ihre databaseURL
sein und bei Verwendung von Supabase sollte es Ihre Projekt-URL sein.
Achten Sie auf Gleichgesinnte, die dem Raum beitreten:
room . onPeerJoin ( peerId => console . log ( ` ${ peerId } joined` ) )
Achten Sie auf Gleichaltrige, die den Raum verlassen:
room . onPeerLeave ( peerId => console . log ( ` ${ peerId } left` ) )
Hören Sie auf Kollegen, die ihre Audio-/Videostreams senden:
room . onPeerStream (
( stream , peerId ) => ( peerElements [ peerId ] . video . srcObject = stream )
)
Um sich von Veranstaltungen abzumelden, verlassen Sie den Raum:
room . leave ( )
Sie können auf die Peer-ID des lokalen Benutzers zugreifen, indem Sie selfId
wie folgt importieren:
import { selfId } from ' trystero '
console . log ( `my peer ID is ${ selfId } ` )
Senden Sie Ihren Videostream an Kollegen:
room . addStream (
await navigator . mediaDevices . getUserMedia ( { audio : true , video : true } )
)
Senden und abonnieren Sie benutzerdefinierte P2P-Aktionen:
const [ sendDrink , getDrink ] = room . makeAction ( 'drink' )
// buy drink for a friend
sendDrink ( { drink : 'negroni' , withIce : true } , friendId )
// buy round for the house (second argument omitted)
sendDrink ( { drink : 'mezcal' , withIce : false } )
// listen for drinks sent to you
getDrink ( ( data , peerId ) =>
console . log (
`got a ${ data . drink } with ${ data . withIce ? '' : 'out' } ice from ${ peerId } `
)
)
Sie können Aktionen auch zum Senden von Binärdaten wie Bildern verwenden:
const [ sendPic , getPic ] = room . makeAction ( 'pic' )
// blobs are automatically handled, as are any form of TypedArray
canvas . toBlob ( blob => sendPic ( blob ) )
// binary data is received as raw ArrayBuffers so your handling code should
// interpret it in a way that makes sense
getPic (
( data , peerId ) => ( imgs [ peerId ] . src = URL . createObjectURL ( new Blob ( [ data ] ) ) )
)
Nehmen wir an, wir möchten, dass Benutzer sich selbst einen Namen geben können:
const idsToNames = { }
const [ sendName , getName ] = room . makeAction ( 'name' )
// tell other peers currently in the room our name
sendName ( 'Oedipa' )
// tell newcomers
room . onPeerJoin ( peerId => sendName ( 'Oedipa' , peerId ) )
// listen for peers naming themselves
getName ( ( name , peerId ) => ( idsToNames [ peerId ] = name ) )
room . onPeerLeave ( peerId =>
console . log ( ` ${ idsToNames [ peerId ] || 'a weird stranger' } left` )
)
Aktionen sind intelligent und kümmern sich hinter den Kulissen um Serialisierung und Chunking. Dies bedeutet, dass Sie sehr große Dateien senden können und alle Daten, die Sie senden, auf der anderen Seite als denselben Typ empfangen werden (eine Zahl als Zahl, eine Zeichenfolge als Zeichenfolge, ein Objekt als Objekt, binär als binär usw.). .
Hier ist ein einfaches Beispiel, wie Sie einen Audio-Chatroom erstellen können:
// this object can store audio instances for later
const peerAudios = { }
// get a local audio stream from the microphone
const selfStream = await navigator . mediaDevices . getUserMedia ( {
audio : true ,
video : false
} )
// send stream to peers currently in the room
room . addStream ( selfStream )
// send stream to peers who join later
room . onPeerJoin ( peerId => room . addStream ( selfStream , peerId ) )
// handle streams from other peers
room . onPeerStream ( ( stream , peerId ) => {
// create an audio instance and set the incoming stream
const audio = new Audio ( )
audio . srcObject = stream
audio . autoplay = true
// add the audio to peerAudio object if you want to address it for something
// later (volume, etc.)
peerAudios [ peerId ] = audio
} )
Das Gleiche gilt auch für Videos. Achten Sie jedoch darauf, eingehende Streams zu Videoelementen im DOM hinzuzufügen:
const peerVideos = { }
const videoContainer = document . getElementById ( 'videos' )
room . onPeerStream ( ( stream , peerId ) => {
let video = peerVideos [ peerId ]
// if this peer hasn't sent a stream before, create a video element
if ( ! video ) {
video = document . createElement ( 'video' )
video . autoplay = true
// add video element to the DOM
videoContainer . appendChild ( video )
}
video . srcObject = stream
peerVideos [ peerId ] = video
} )
Angenommen, Ihre App unterstützt das Senden verschiedener Dateitypen und Sie möchten die gesendeten Rohbytes mit Metadaten dazu versehen, wie sie interpretiert werden sollen. Anstatt manuell Metadatenbytes zum Puffer hinzuzufügen, können Sie einfach ein Metadatenargument in der Absenderaktion für Ihre binäre Nutzlast übergeben:
const [ sendFile , getFile ] = makeAction ( 'file' )
getFile ( ( data , peerId , metadata ) =>
console . log (
`got a file ( ${ metadata . name } ) from ${ peerId } with type ${ metadata . type } ` ,
data
)
)
// to send metadata, pass a third argument
// to broadcast to the whole room, set the second peer ID argument to null
sendFile ( buffer , null , { name : 'The Courierʼs Tragedy' , type : 'application/pdf' } )
Aktionssenderfunktionen geben ein Versprechen zurück, das aufgelöst wird, wenn sie mit dem Senden fertig sind. Sie können dies optional verwenden, um dem Benutzer anzuzeigen, wenn eine große Übertragung durchgeführt wird.
await sendFile ( amplePayload )
console . log ( 'done sending to all peers' )
Aktionssenderfunktionen verfügen außerdem über eine optionale Rückruffunktion, die im Verlauf der Übertragung kontinuierlich aufgerufen wird. Dies kann verwendet werden, um dem Absender bei großen Übertragungen einen Fortschrittsbalken anzuzeigen. Der Callback wird mit einem Prozentwert zwischen 0 und 1 und der ID des empfangenden Peers aufgerufen:
sendFile (
payload ,
// notice the peer target argument for any action sender can be a single peer
// ID, an array of IDs, or null (meaning send to all peers in the room)
[ peerIdA , peerIdB , peerIdC ] ,
// metadata, which can also be null if you're only interested in the
// progress handler
{ filename : 'paranoids.flac' } ,
// assuming each peer has a loading bar added to the DOM, its value is
// updated here
( percent , peerId ) => ( loadingBars [ peerId ] . value = percent )
)
Ebenso können Sie als Empfänger wie folgt auf Fortschrittsereignisse warten:
const [ sendFile , getFile , onFileProgress ] = room . makeAction ( 'file' )
onFileProgress ( ( percent , peerId , metadata ) =>
console . log (
` ${ percent * 100 } % done receiving ${ metadata . filename } from ${ peerId } `
)
)
Beachten Sie, dass alle Metadaten mit Fortschrittsereignissen gesendet werden, sodass Sie dem empfangenden Benutzer möglicherweise mit dem Namen der eingehenden Datei anzeigen können, dass eine Übertragung im Gange ist.
Da ein Peer mehrere Übertragungen parallel senden kann, können Sie diese auch mithilfe von Metadaten unterscheiden, z. B. durch das Senden einer eindeutigen ID.
Sobald Peers miteinander verbunden sind, ist ihre gesamte Kommunikation Ende-zu-Ende-verschlüsselt. Während des ersten Verbindungs-/Erkennungsprozesses werden die SDPs der Peers über das ausgewählte Peering-Strategiemedium gesendet. Standardmäßig wird das SDP mit einem aus Ihrer App-ID und Raum-ID abgeleiteten Schlüssel verschlüsselt, um zu verhindern, dass Klartext-Sitzungsdaten in Protokollen angezeigt werden. Dies ist für die meisten Anwendungsfälle in Ordnung, ein Relay-Strategie-Betreiber kann den Schlüssel jedoch anhand der Raum- und App-IDs rückentwickeln. Eine sicherere Option besteht darin, im App-Konfigurationsobjekt einen password
zu übergeben, der zum Ableiten des Verschlüsselungsschlüssels verwendet wird:
joinRoom ( { appId : 'kinneret' , password : 'MuchoMaa$' } , 'w_a_s_t_e__v_i_p' )
Dies ist ein gemeinsames Geheimnis, das im Voraus bekannt sein muss und das Passwort muss für alle Peers im Raum übereinstimmen, damit sie eine Verbindung herstellen können. Ein Beispielanwendungsfall könnte ein privater Chatroom sein, in dem Benutzer das Passwort über externe Mittel erfahren.
trystero -Funktionen sind idempotent, sodass sie bereits als React-Hooks funktionieren.
Hier ist eine einfache Beispielkomponente, bei der jeder Peer seine Lieblingsfarbe mit allen anderen synchronisiert:
import { joinRoom } from ' trystero '
import { useState } from 'react'
const trystero Config = { appId : 'thurn-und-taxis' }
export default function App ( { roomId } ) {
const room = joinRoom ( trystero Config , roomId )
const [ sendColor , getColor ] = room . makeAction ( 'color' )
const [ myColor , setMyColor ] = useState ( '#c0ffee' )
const [ peerColors , setPeerColors ] = useState ( { } )
// whenever new peers join the room, send my color to them:
room . onPeerJoin ( peer => sendColor ( myColor , peer ) )
// listen for peers sending their colors and update the state accordingly:
getColor ( ( color , peer ) =>
setPeerColors ( peerColors => ( { ... peerColors , [ peer ] : color } ) )
)
const updateColor = e => {
const { value } = e . target
// when updating my own color, broadcast it to all peers:
sendColor ( value )
setMyColor ( value )
}
return (
< >
< h1 > trystero + React </ h1 >
< h2 > My color: </ h2 >
< input type = "color" value = { myColor } onChange = { updateColor } />
< h2 > Peer colors: </ h2 >
< ul >
{ Object . entries ( peerColors ) . map ( ( [ peerId , color ] ) => (
< li key = { peerId } style = { { backgroundColor : color } } >
{ peerId } : { color }
</ li >
) ) }
</ ul >
</ >
)
}
Aufmerksamen Lesern fällt vielleicht auf, dass das obige Beispiel einfach ist und nicht berücksichtigt, ob wir die Raum-ID der Komponente ändern oder die Bereitstellung aufheben möchten. Für diese Szenarien können Sie diesen einfachen useRoom()
-Hook verwenden, der sich entsprechend von Raumereignissen abmeldet:
import { joinRoom } from ' trystero '
import { useEffect , useRef } from 'react'
export const useRoom = ( roomConfig , roomId ) => {
const roomRef = useRef ( joinRoom ( roomConfig , roomId ) )
const lastRoomIdRef = useRef ( roomId )
useEffect ( ( ) => {
if ( roomId !== lastRoomIdRef . current ) {
roomRef . current . leave ( )
roomRef . current = joinRoom ( roomConfig , roomId )
lastRoomIdRef . current = roomId
}
return ( ) => roomRef . current . leave ( )
} , [ roomConfig , roomId ] )
return roomRef . current
}
So verwenden Sie die Supabase-Strategie:
appId
in der trystero -Konfiguration fest, kopieren Sie den anon public
API-Schlüssel und legen Sie ihn in der trystero -Konfiguration als supabaseKey
festWenn Sie die Firebase-Strategie verwenden möchten und kein bestehendes Projekt haben:
databaseURL
und verwenden Sie sie als appId
in Ihrer trystero -Konfiguration{
"rules" : {
".read" : false ,
".write" : false ,
"__ trystero __" : {
".read" : false ,
".write" : false ,
"$room_id" : {
".read" : true ,
".write" : true
}
}
}
}
Diese Regeln stellen sicher, dass die Anwesenheit von Raum-Peers nur dann lesbar ist, wenn der Raum-Namespace im Voraus bekannt ist.
joinRoom(config, roomId, [onError])
Fügt einen lokalen Benutzer zum Raum hinzu, wobei andere Peers im selben Namensraum Kommunikationskanäle öffnen und Ereignisse senden. Wenn Sie joinRoom()
mehrmals mit demselben Namespace aufrufen, wird dieselbe Rauminstanz zurückgegeben.
config
– Konfigurationsobjekt, das die folgenden Schlüssel enthält:
appId
– (erforderlich) Eine eindeutige Zeichenfolge, die Ihre App identifiziert. Wenn Sie Supabase verwenden, sollte dies auf Ihre Projekt-URL eingestellt sein (siehe Supabase-Einrichtungsanweisungen). Wenn Sie Firebase verwenden, sollte dies die databaseURL
aus Ihrer Firebase-Konfiguration sein (siehe auch firebaseApp
unten für eine alternative Möglichkeit zur Konfiguration der Firebase-Strategie).
password
– (optional) Eine Zeichenfolge zum Verschlüsseln von Sitzungsbeschreibungen über AES-GCM, während sie durch das Peering-Medium weitergeleitet werden. Wenn nicht festgelegt, werden Sitzungsbeschreibungen mit einem Schlüssel verschlüsselt, der aus der App-ID und dem Raumnamen abgeleitet wird. Für die Verbindung zwischen allen Peers im Raum muss ein benutzerdefiniertes Passwort übereinstimmen. Weitere Einzelheiten finden Sie unter Verschlüsselung.
rtcConfig
– (optional) Gibt eine benutzerdefinierte RTCConfiguration
für alle Peer-Verbindungen an.
relayUrls
– (optional, ? BitTorrent, ? Nostr, ? Nur MQTT) Benutzerdefinierte Liste von URLs für die Strategie, die zum Bootstrapping von P2P-Verbindungen verwendet werden soll. Dies wären jeweils BitTorrent-Tracker, Nostr-Relays und MQTT-Broker. Sie müssen sichere WebSocket-Verbindungen unterstützen.
relayRedundancy
– (optional, ? BitTorrent, ? Nostr, ? Nur MQTT) Ganzzahl, die angibt, mit wie vielen Torrent-Trackern gleichzeitig eine Verbindung hergestellt werden soll, falls einige ausfallen. Die Übergabe einer relayUrls
“-Option führt dazu, dass diese Option ignoriert wird, da die gesamte Liste verwendet wird.
supabaseKey
– (erforderlich, ⚡️ nur Supabase) anon public
API-Schlüssel Ihres Supabase-Projekts.
firebaseApp
– (optional, nur Firebase) Sie können eine bereits initialisierte Firebase-App-Instanz anstelle einer appId
übergeben. Normalerweise initialisiert trystero eine Firebase-App basierend auf der appId
Dies schlägt jedoch fehl, wenn Sie sie bereits für die Verwendung an anderer Stelle initialisiert haben.
rootPath
– (optional, nur Firebase) Zeichenfolge, die den Pfad angibt, in trystero seine Matchmaking-Daten in Ihre Datenbank schreibt (standardmäßig '__ trystero __'
). Dies zu ändern ist nützlich, wenn Sie mehrere Apps mit derselben Datenbank ausführen möchten und sich keine Sorgen über Namespace-Kollisionen machen möchten.
libp2pConfig
– (optional, ? Nur IPFS) Libp2pOptions
, wo Sie eine Liste statischer Peers für das Bootstrapping angeben können.
roomId
– Eine Zeichenfolge zum Benennen von Peers und Ereignissen innerhalb eines Raums.
onError(details)
– (optional) Eine Rückruffunktion, die aufgerufen wird, wenn der Raum aufgrund eines falschen Passworts nicht betreten werden kann. details
ist ein Objekt mit appId
, roomId
, peerId
und error
das den Fehler beschreibt.
Gibt ein Objekt mit den folgenden Methoden zurück:
leave()
Entfernen Sie den lokalen Benutzer aus dem Raum und melden Sie sich von Raumveranstaltungen ab.
getPeers()
Gibt eine Karte von RTCPeerConnection
s für die im Raum vorhandenen Peers zurück (ohne den lokalen Benutzer). Die Schlüssel dieses Objekts sind die IDs der jeweiligen Peers.
addStream(stream, [targetPeers], [metadata])
Überträgt den Medienstream an andere Peers.
stream
– Ein MediaStream
mit Audio und/oder Video zum Senden an Peers im Raum.
targetPeers
– (optional) Wenn angegeben, wird der Stream nur an die Ziel-Peer-ID (String) oder die Liste der Peer-IDs (Array) gesendet.
metadata
– (optional) Zusätzliche Metadaten (jeder serialisierbare Typ), die mit dem Stream gesendet werden sollen. Dies ist nützlich, wenn Sie mehrere Streams senden, damit die Empfänger wissen, welcher Stream welcher ist (z. B. eine Webcam oder eine Bildschirmaufnahme). Wenn Sie einen Stream mit einem Metadatenargument an alle Peers im Raum senden möchten, übergeben Sie null
als zweites Argument.
removeStream(stream, [targetPeers])
Stoppt das Senden zuvor gesendeter Medienströme an andere Peers.
stream
– Ein zuvor gesendeter MediaStream
um das Senden zu beenden.
targetPeers
– (optional) Wenn angegeben, wird der Stream nur aus der Ziel-Peer-ID (Zeichenfolge) oder der Liste der Peer-IDs (Array) entfernt.
addTrack(track, stream, [targetPeers], [metadata])
Fügt einem Stream einen neuen Medientrack hinzu.
track
– Ein MediaStreamTrack
zum Hinzufügen zu einem vorhandenen Stream.
stream
– Der Ziel MediaStream
an den der neue Titel angehängt werden soll.
targetPeers
– (optional) Wenn angegeben, wird der Track nur an die Ziel-Peer-ID (String) oder die Liste der Peer-IDs (Array) gesendet.
metadata
– (optional) Zusätzliche Metadaten (jeder serialisierbare Typ), die mit dem Track gesendet werden sollen. Weitere Einzelheiten finden Sie oben in metadata
für addStream()
.
removeTrack(track, stream, [targetPeers])
Entfernt einen Medientitel aus einem Stream.
track
– Der zu entfernende MediaStreamTrack
.
stream
– Der MediaStream
an den der Titel angehängt ist.
targetPeers
– (optional) Wenn angegeben, wird der Track nur aus der Ziel-Peer-ID (String) oder der Liste der Peer-IDs (Array) entfernt.
replaceTrack(oldTrack, newTrack, stream, [targetPeers])
Ersetzt eine Medienspur durch eine neue.
oldTrack
– Der zu entfernende MediaStreamTrack
.
newTrack
– Ein MediaStreamTrack
zum Anhängen.
stream
– Der MediaStream
an den der oldTrack
angehängt ist.
targetPeers
– (optional) Wenn angegeben, wird die Spur nur für die Ziel-Peer-ID (Zeichenfolge) oder die Liste der Peer-IDs (Array) ersetzt.
onPeerJoin(callback)
Registriert eine Rückruffunktion, die aufgerufen wird, wenn ein Peer dem Raum beitritt. Bei mehrmaligem Anruf wird immer nur der zuletzt registrierte Rückruf angerufen.
callback(peerId)
– Funktion, die immer dann ausgeführt wird, wenn ein Peer beitritt, aufgerufen mit der ID des Peers.Beispiel:
onPeerJoin ( peerId => console . log ( ` ${ peerId } joined` ) )
onPeerLeave(callback)
Registriert eine Rückruffunktion, die aufgerufen wird, wenn ein Peer den Raum verlässt. Bei mehrmaligem Anruf wird immer nur der zuletzt registrierte Rückruf angerufen.
callback(peerId)
– Funktion, die immer dann ausgeführt wird, wenn ein Peer geht, aufgerufen mit der ID des Peers.Beispiel:
onPeerLeave ( peerId => console . log ( ` ${ peerId } left` ) )
onPeerStream(callback)
Registriert eine Rückruffunktion, die aufgerufen wird, wenn ein Peer einen Medienstream sendet. Bei mehrmaligem Anruf wird immer nur der zuletzt registrierte Rückruf angerufen.
callback(stream, peerId, metadata)
– Funktion, die immer dann ausgeführt wird, wenn ein Peer einen Medienstream sendet, aufgerufen mit dem Stream, der ID und optionalen Metadaten des Peers (Einzelheiten siehe addStream()
oben).Beispiel:
onPeerStream ( ( stream , peerId ) =>
console . log ( `got stream from ${ peerId } ` , stream )
)
onPeerTrack(callback)
Registriert eine Rückruffunktion, die aufgerufen wird, wenn ein Peer einen Medientrack sendet. Bei mehrmaligem Anruf wird immer nur der zuletzt registrierte Rückruf angerufen.
callback(track, stream, peerId, metadata)
– Funktion, die immer dann ausgeführt wird, wenn ein Peer einen Medientrack sendet, aufgerufen mit dem Track des Peers, dem angehängten Stream, der ID und optionalen Metadaten (siehe addTrack()
oben für Details).Beispiel:
onPeerTrack ( ( track , stream , peerId ) =>
console . log ( `got track from ${ peerId } ` , track )
)
makeAction(actionId)
Hören Sie auf benutzerdefinierte Datenaktionen und senden Sie diese.
actionId
– Eine Zeichenfolge, um diese Aktion bei allen Peers konsistent zu registrieren.Gibt ein Array mit drei Funktionen zurück:
Sendet Daten an Peers und gibt ein Versprechen zurück, das aufgelöst wird, wenn alle Ziel-Peers mit dem Datenempfang fertig sind.
(data, [targetPeers], [metadata], [onProgress])
data
– Beliebiger zu sendender Wert (primitiv, Objekt, binär). Serialisierung und Chunking werden automatisch durchgeführt. Binärdaten (z. B. Blob
, TypedArray
) werden von anderen Peers als agnostischer ArrayBuffer
empfangen.
targetPeers
– (optional) Entweder eine Peer-ID (Zeichenfolge), ein Array von Peer-IDs oder null
(was angibt, dass an alle Peers im Raum gesendet werden soll).
metadata
– (optional) Wenn die Daten binär sind, können Sie ein optionales Metadatenobjekt senden, das sie beschreibt (siehe Binäre Metadaten).
onProgress
– (optional) Eine Rückruffunktion, die aufgerufen wird, wenn jeder Block für jeden Peer übertragen wird. Die Funktion wird mit einem Wert zwischen 0 und 1 und einer Peer-ID aufgerufen. Ein Beispiel finden Sie unter Fortschrittsaktualisierungen.
Registriert eine Rückruffunktion, die ausgeführt wird, wenn Daten für diese Aktion von anderen Peers empfangen werden.
(data, peerId, metadata)
data
– Der vom sendenden Peer übertragene Wert. Die Deserialisierung erfolgt automatisch, d. h. eine Zahl wird als Zahl, ein Objekt als Objekt usw. empfangen.
peerId
– Die ID-Zeichenfolge des sendenden Peers.
metadata
– (optional) Optionales Metadatenobjekt, das vom Absender bereitgestellt wird, wenn data
binär sind, z. B. ein Dateiname.
Registriert eine Rückruffunktion, die ausgeführt wird, wenn Teildaten von Peers empfangen werden. Sie können dies zum Verfolgen großer binärer Übertragungen verwenden. Ein Beispiel finden Sie unter Fortschrittsaktualisierungen.
(percent, peerId, metadata)
percent
– Eine Zahl zwischen 0 und 1, die den Prozentsatz angibt, zu dem die Übertragung abgeschlossen ist.
peerId
– Die ID-Zeichenfolge des sendenden Peers.
metadata
– (optional) Optionales Metadatenobjekt, das vom Absender bereitgestellt wird.
Beispiel:
const [ sendCursor , getCursor ] = room . makeAction ( 'cursormove' )
window . addEventListener ( 'mousemove' , e => sendCursor ( [ e . clientX , e . clientY ] ) )
getCursor ( ( [ x , y ] , peerId ) => {
const peerCursor = cursorMap [ peerId ]
peerCursor . style . left = x + 'px'
peerCursor . style . top = y + 'px'
} )
ping(peerId)
Nimmt eine Peer-ID und gibt ein Versprechen zurück, das in Millisekunden aufgelöst wird, die der Roundtrip zu diesem Peer gedauert hat. Verwenden Sie dies zum Messen der Latenz.
peerId
– Peer-ID-Zeichenfolge des Ziel-Peers.Beispiel:
// log round-trip time every 2 seconds
room . onPeerJoin ( peerId =>
setInterval (
async ( ) => console . log ( `took ${ await room . ping ( peerId ) } ms` ) ,
2000
)
)
selfId
Eine eindeutige ID-Zeichenfolge, mit der andere Peers den lokalen Benutzer als auch raumübergreifend global kennen.
getRelaySockets()
(? BitTorrent, ? Nostr, ? Nur MQTT) Gibt ein Objekt von Relay-URL-Schlüsseln zurück, die ihren WebSocket-Verbindungen zugeordnet sind. Dies kann nützlich sein, um den Status der Verbindung des Benutzers zu den Relais zu ermitteln und etwaige Verbindungsfehler zu behandeln.
Beispiel:
console . log ( trystero . getRelaySockets ( ) )
// => Object {
// "wss://tracker.webtorrent.dev": WebSocket,
// "wss://tracker.openwebtorrent.com": WebSocket
// }
getOccupants(config, roomId)
(Nur Firebase) Gibt ein Versprechen zurück, das in eine Liste der im angegebenen Namespace vorhandenen Benutzer-IDs aufgelöst wird. Dies ist nützlich, um zu überprüfen, wie viele Benutzer sich in einem Raum befinden, ohne diesem beizutreten.
config
– Ein KonfigurationsobjektroomId
– Eine Namespace-Zeichenfolge, die Sie an joinRoom()
übergeben würden.Beispiel:
console . log ( ( await trystero . getOccupants ( config , 'the_scope' ) ) . length )
// => 3
einmalige Einrichtung¹ | Bündelgröße² | Zeit, sich zu verbinden³ | |
---|---|---|---|
? Nostr | keine? | 54K | ⏱️⏱️ |
? MQTT | keine? | 332K | ⏱️⏱️ |
? BitTorrent | keine? | 25.000 ? | ⏱️⏱️ |
⚡️ Supabase | ~5 Min | 150.000 | ⏱️ ? |
Feuerbasis | ~5 Min | 177K | ⏱️ ? |
? IPFS | keine? | 945K | ⏱️⏱️ |
¹ Alle Strategien außer Firebase erfordern keine Einrichtung. Firebase ist eine verwaltete Strategie, die die Einrichtung eines Kontos erfordert.
² Berechnet über Rollup-Bündelung + Terser-Komprimierung.
³ Relative Geschwindigkeit der Peers, die sich miteinander verbinden, wenn sie einem Raum beitreten. Firebase ist nahezu augenblicklich, während die anderen Strategien beim Austausch von Peering-Informationen etwas langsamer sind.
Der einzigartige Vorteil von trystero besteht darin, dass keine Backend-Einrichtung erforderlich ist und in den meisten Fällen eine dezentrale Infrastruktur verwendet wird. Dies ermöglicht ein reibungsloses Experimentieren und verhindert einen Single Point of Failure. Ein potenzieller Nachteil besteht darin, dass es schwierig ist, sicherzustellen, dass die öffentliche Infrastruktur, die es nutzt, immer hochverfügbar ist, selbst mit den Redundanztechniken, die trystero verwendet. Während die anderen Strategien dezentralisiert sind, handelt es sich bei den Supabase- und Firebase-Strategien um einen stärker verwalteten Ansatz mit größerer Kontrolle und einem SLA, der möglicherweise besser für „Produktions“-Apps geeignet ist.
trystero macht es einfach, zwischen Strategien zu wechseln – ändern Sie einfach eine einzelne Importzeile und experimentieren Sie schnell:
import { joinRoom } from ' trystero /[torrent|nostr|mqtt|supabase|firebase|ipfs]'
trystero von Dan Motzenbecker