Создавайте мгновенные многопользовательские веб-приложения без необходимости использования сервера.
ПОПРОБУЙТЕ ДЕМО ?
trystero управляет тайной курьерской сетью, которая позволяет пользователям вашего приложения напрямую общаться друг с другом, в зашифрованном виде и без посредника на сервере.
В сети полно открытых, децентрализованных каналов связи: торрент-трекеры, брокеры устройств IoT, специализированные файловые протоколы и нишевые социальные сети.
trystero подключается к этим сетям, чтобы автоматически устанавливать безопасные частные p2p-соединения между пользователями вашего приложения без каких-либо усилий с вашей стороны.
Пиры могут подключаться через? БитТоррент, ? Ностр, ? MQTT, ⚡️ Supabase, Firebase или ? IPFS – все используют один и тот же API.
Помимо автоматического сопоставления одноранговых узлов, trystero предлагает несколько интересных абстракций поверх WebRTC:
Здесь вы можете увидеть, что люди создают с помощью trystero .
Если вы просто хотите попробовать trystero , вы можете пропустить это объяснение и сразу приступить к его использованию.
Чтобы установить прямое одноранговое соединение с WebRTC, необходим сигнальный канал для обмена информацией об одноранговых узлах (SDP). Обычно это предполагает запуск собственного сервера подбора игроков, но trystero абстрагирует это для вас и предлагает несколько «бессерверных» стратегий для подключения одноранговых узлов (в настоящее время BitTorrent, Nostr, MQTT, Supabase, Firebase и IPFS).
Важным моментом, который следует запомнить, является следующее:
Помимо обнаружения одноранговых узлов, данные вашего приложения никогда не затрагивают стратегическую среду и передаются напрямую в одноранговой сети и в сквозном зашифрованном виде между пользователями.
?
Здесь вы можете сравнить стратегии.
Вы можете установить с помощью npm ( npm i trystero
) и импортировать следующим образом:
import { joinRoom } from ' trystero '
Или, может быть, вы предпочитаете простой тег сценария? Загрузите готовый JS-файл последней версии и импортируйте его локально:
< script type =" module " >
import { joinRoom } from './ trystero -torrent.min.js'
</ script >
По умолчанию используется стратегия Nostr. Чтобы использовать другой, просто выполните глубокий импорт (ваш сборщик должен обрабатывать включение только соответствующего кода):
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)
Затем присоедините пользователя к комнате с идентификатором:
const config = { appId : 'san_narciso_3d' }
const room = joinRoom ( config , 'yoyodyne' )
Первый аргумент — это объект конфигурации, которому требуется appId
. Это должен быть совершенно уникальный идентификатор вашего приложения¹. Второй аргумент — это идентификатор комнаты.
Почему номера? Браузеры могут одновременно обрабатывать только ограниченное количество соединений WebRTC, поэтому рекомендуется спроектировать приложение таким образом, чтобы пользователи были разделены на группы (или комнаты, или пространства имен, или каналы... как бы вы их ни называли).
¹ При использовании Firebase appId
должен быть databaseURL
, а при использовании Supabase — URL-адресом вашего проекта.
Послушайте, как сверстники присоединяются к комнате:
room . onPeerJoin ( peerId => console . log ( ` ${ peerId } joined` ) )
Послушайте, как сверстники выходят из комнаты:
room . onPeerLeave ( peerId => console . log ( ` ${ peerId } left` ) )
Слушайте пиры, отправляющие свои аудио/видео потоки:
room . onPeerStream (
( stream , peerId ) => ( peerElements [ peerId ] . video . srcObject = stream )
)
Чтобы отписаться от событий, покиньте комнату:
room . leave ( )
Вы можете получить доступ к идентификатору узла локального пользователя, импортировав selfId
следующим образом:
import { selfId } from ' trystero '
console . log ( `my peer ID is ${ selfId } ` )
Отправьте коллегам свой видеопоток:
room . addStream (
await navigator . mediaDevices . getUserMedia ( { audio : true , video : true } )
)
Отправляйте и подписывайтесь на пользовательские действия P2P:
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 } `
)
)
Вы также можете использовать действия для отправки двоичных данных, например изображений:
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 ] ) ) )
)
Допустим, мы хотим, чтобы пользователи могли называть себя:
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` )
)
Действия являются интеллектуальными и позволяют выполнять сериализацию и фрагментацию за кулисами. Это означает, что вы можете отправлять очень большие файлы, и любые отправленные вами данные будут получены на другой стороне как тот же тип (число как число, строка как строка, объект как объект, двоичный файл как двоичный файл и т. д.). .
Вот простой пример того, как можно создать аудиочат:
// 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
} )
То же самое можно сделать и с видео, только обязательно добавьте входящие потоки к элементам видео в DOM:
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
} )
Допустим, ваше приложение поддерживает отправку различных типов файлов, и вы хотите аннотировать отправляемые необработанные байты метаданными о том, как их следует интерпретировать. Вместо того, чтобы вручную добавлять байты метаданных в буфер, вы можете просто передать аргумент метаданных в действии отправителя для вашей двоичной полезной нагрузки:
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' } )
Функции-отправители действий возвращают обещание, которое выполняется после завершения отправки. При желании вы можете использовать это, чтобы указать пользователю, когда выполнена большая передача.
await sendFile ( amplePayload )
console . log ( 'done sending to all peers' )
Функции отправителя действий также принимают дополнительную функцию обратного вызова, которая будет постоянно вызываться по мере продвижения передачи. Это можно использовать для отображения индикатора выполнения отправителю при больших переводах. Обратный вызов вызывается с процентным значением от 0 до 1 и идентификатором принимающего узла:
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 )
)
Аналогичным образом вы можете прослушивать события прогресса в качестве получателя следующим образом:
const [ sendFile , getFile , onFileProgress ] = room . makeAction ( 'file' )
onFileProgress ( ( percent , peerId , metadata ) =>
console . log (
` ${ percent * 100 } % done receiving ${ metadata . filename } from ${ peerId } `
)
)
Обратите внимание, что любые метаданные отправляются вместе с событиями хода выполнения, поэтому вы можете показать принимающему пользователю, что идет передача, возможно, с указанием имени входящего файла.
Поскольку одноранговый узел может отправлять несколько передач параллельно, вы также можете использовать метаданные, чтобы различать их, например, отправляя уникальный идентификатор.
Как только одноранговые узлы соединяются друг с другом, все их сообщения шифруются сквозным шифрованием. Во время первоначального процесса подключения/обнаружения SDP одноранговых узлов отправляются через выбранную среду пиринговой стратегии. По умолчанию SDP шифруется с использованием ключа, полученного на основе идентификатора вашего приложения и идентификатора комнаты, чтобы предотвратить появление данных сеанса в виде открытого текста в журналах. Это подходит для большинства случаев использования, однако оператор стратегии ретрансляции может перепроектировать ключ, используя идентификаторы комнаты и приложения. Более безопасный вариант — передать параметр password
в объекте конфигурации приложения, который будет использоваться для получения ключа шифрования:
joinRoom ( { appId : 'kinneret' , password : 'MuchoMaa$' } , 'w_a_s_t_e__v_i_p' )
Это общий секрет, который необходимо знать заранее, а пароль должен совпадать для всех узлов в комнате, чтобы они могли подключиться. Примером использования может быть частный чат, где пользователи узнают пароль с помощью внешних средств.
Функции trystero идемпотентны, поэтому они уже «из коробки» работают как перехватчики React.
Вот простой пример компонента, в котором каждый одноранговый узел синхронизирует свой любимый цвет со всеми остальными:
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 >
</ >
)
}
Внимательные читатели могут заметить, что приведенный выше пример прост и не учитывает, хотим ли мы изменить идентификатор комнаты компонента или отключить его. Для этих сценариев вы можете использовать этот простой хук useRoom()
, который соответственно отписывается от событий комнаты:
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
}
Чтобы использовать стратегию Supabase:
appId
в конфигурации trystero , скопируйте anon public
и установите его как supabaseKey
в конфигурации trystero .Если вы хотите использовать стратегию Firebase и у вас нет существующего проекта:
databaseURL
и используйте его в качестве идентификатора appId
в конфигурации trystero .{
"rules" : {
".read" : false ,
".write" : false ,
"__ trystero __" : {
".read" : false ,
".write" : false ,
"$room_id" : {
".read" : true ,
".write" : true
}
}
}
}
Эти правила гарантируют, что присутствие однорангового узла комнаты будет доступно для чтения только в том случае, если пространство имен комнаты известно заранее.
joinRoom(config, roomId, [onError])
Добавляет локального пользователя в комнату, благодаря чему другие узлы в том же пространстве имен будут открывать каналы связи и отправлять события. Вызов joinRoom()
несколько раз с одним и тем же пространством имен вернет один и тот же экземпляр комнаты.
config
— объект конфигурации, содержащий следующие ключи:
appId
— (обязательно) уникальная строка, идентифицирующая ваше приложение. При использовании Supabase в качестве этого параметра следует указать URL-адрес вашего проекта (см. инструкции по настройке Supabase). Если вы используете Firebase, это должен быть databaseURL
из вашей конфигурации Firebase (альтернативный способ настройки стратегии Firebase также см. ниже в firebaseApp
).
password
— (необязательно) Строка для шифрования описаний сеансов через AES-GCM при их передаче через пиринговую среду. Если этот параметр не установлен, описания сеансов будут зашифрованы с помощью ключа, полученного из идентификатора приложения и названия комнаты. Пользовательский пароль должен совпадать между всеми узлами в комнате, чтобы они могли подключиться. См. шифрование для более подробной информации.
rtcConfig
— (необязательно) Указывает пользовательскую RTCConfiguration
для всех одноранговых соединений.
relayUrls
- (необязательно, только ? BitTorrent, ? Nostr, ? MQTT) Пользовательский список URL-адресов для стратегии, которая будет использоваться для начальной загрузки P2P-соединений. Это будут трекеры BitTorrent, ретрансляторы Nostr и брокеры MQTT соответственно. Они должны поддерживать безопасные соединения WebSocket.
relayRedundancy
- (необязательно, только ? BitTorrent, ? Nostr, ? MQTT) Целое число, указывающее, к скольким торрент-трекерам следует подключаться одновременно в случае сбоя некоторых из них. Передача опции relayUrls
приведет к тому, что эта опция будет проигнорирована, поскольку будет использоваться весь список.
supabaseKey
— (обязательно, ⚡️ только Supabase) anon public
API-ключ вашего проекта Supabase.
firebaseApp
— (необязательно, только для Firebase). Вместо appId
можно передать уже инициализированный экземпляр приложения Firebase. Обычно trystero инициализирует приложение Firebase на основе appId
, но это не удастся, если вы уже инициализировали его для использования в другом месте.
rootPath
— (необязательно, только для Firebase) Строка, определяющая путь, по которому trystero записывает свои данные о поиске игроков в вашу базу данных (по умолчанию '__ trystero __'
). Изменение этого значения полезно, если вы хотите запускать несколько приложений, используя одну и ту же базу данных, и не хотите беспокоиться о конфликтах пространств имен.
libp2pConfig
— (необязательно, только для IPFS) Libp2pOptions
, где вы можете указать список статических одноранговых узлов для начальной загрузки.
roomId
— строка для одноранговых узлов пространства имен и событий в комнате.
onError(details)
— (необязательно) Функция обратного вызова, которая будет вызвана, если к комнате невозможно присоединиться из-за неправильного пароля. details
— это объект, содержащий appId
, roomId
, peerId
и error
, описывающий ошибку.
Возвращает объект следующими методами:
leave()
Удалить локального пользователя из комнаты и отписаться от событий комнаты.
getPeers()
Возвращает карту RTCPeerConnection
для одноранговых узлов, присутствующих в комнате (не включая локального пользователя). Ключами этого объекта являются идентификаторы соответствующих узлов.
addStream(stream, [targetPeers], [metadata])
Транслирует медиапоток другим узлам.
stream
— MediaStream
с аудио и/или видео для отправки одноранговым узлам в комнате.
targetPeers
— (необязательно). Если указано, поток отправляется только по идентификатору целевого узла (строка) или списку идентификаторов узла (массив).
metadata
— (необязательно) Дополнительные метаданные (любого сериализуемого типа), которые будут отправлены вместе с потоком. Это полезно при отправке нескольких потоков, чтобы получатели знали, какой из них есть какой (например, веб-камера или снимок экрана). Если вы хотите транслировать поток всем узлам в комнате с аргументом метаданных, передайте null
в качестве второго аргумента.
removeStream(stream, [targetPeers])
Останавливает отправку ранее отправленного медиапотока другим узлам.
stream
— ранее отправленный MediaStream
для прекращения отправки.
targetPeers
— (необязательно). Если указано, поток удаляется только из идентификатора целевого узла (строка) или списка идентификаторов узла (массив).
addTrack(track, stream, [targetPeers], [metadata])
Добавляет новую медиа-дорожку в поток.
track
— MediaStreamTrack
для добавления к существующему потоку.
stream
— целевой MediaStream
к которому нужно прикрепить новую дорожку.
targetPeers
— (необязательно) Если указано, трек отправляется только по идентификатору целевого узла (строка) или списку идентификаторов узла (массив).
metadata
— (необязательно) Дополнительные метаданные (любого сериализуемого типа), которые будут отправлены вместе с треком. Дополнительные сведения см. в примечаниях metadata
для addStream()
выше.
removeTrack(track, stream, [targetPeers])
Удаляет медиа-дорожку из потока.
track
— MediaStreamTrack
который нужно удалить.
stream
— MediaStream
к которому прикреплен трек.
targetPeers
— (необязательно) Если указано, отслеживание удаляется только из идентификатора целевого узла (строка) или списка идентификаторов узла (массив).
replaceTrack(oldTrack, newTrack, stream, [targetPeers])
Заменяет медиа-трек на новый.
oldTrack
— MediaStreamTrack
который необходимо удалить.
newTrack
— MediaStreamTrack
для присоединения.
stream
— MediaStream
к которому подключен oldTrack
.
targetPeers
— (необязательно) Если указано, дорожка заменяется только для идентификатора целевого узла (строка) или списка идентификаторов узла (массив).
onPeerJoin(callback)
Регистрирует функцию обратного вызова, которая будет вызываться, когда одноранговый узел присоединяется к комнате. Если вызывается более одного раза, вызывается только последний зарегистрированный обратный вызов.
callback(peerId)
— функция, запускаемая при каждом присоединении узла, вызываемая с идентификатором узла.Пример:
onPeerJoin ( peerId => console . log ( ` ${ peerId } joined` ) )
onPeerLeave(callback)
Регистрирует функцию обратного вызова, которая будет вызываться, когда одноранговый узел покидает комнату. Если вызывается более одного раза, вызывается только последний зарегистрированный обратный вызов.
callback(peerId)
— функция, запускаемая при выходе узла, вызываемая с идентификатором узла.Пример:
onPeerLeave ( peerId => console . log ( ` ${ peerId } left` ) )
onPeerStream(callback)
Регистрирует функцию обратного вызова, которая будет вызываться, когда одноранговый узел отправляет медиапоток. Если вызывается более одного раза, вызывается только последний зарегистрированный обратный вызов.
callback(stream, peerId, metadata)
— функция, которая запускается всякий раз, когда одноранговый узел отправляет медиапоток, вызываемый с потоком, идентификатором и дополнительными метаданными узла (подробнее см. выше addStream()
).Пример:
onPeerStream ( ( stream , peerId ) =>
console . log ( `got stream from ${ peerId } ` , stream )
)
onPeerTrack(callback)
Регистрирует функцию обратного вызова, которая будет вызываться, когда одноранговый узел отправляет мультимедийную дорожку. Если вызывается более одного раза, вызывается только последний зарегистрированный обратный вызов.
callback(track, stream, peerId, metadata)
— функция, запускаемая всякий раз, когда одноранговый узел отправляет медиа-трек, вызываемый с треком однорангового узла, прикрепленным потоком, идентификатором и дополнительными метаданными (подробности см. addTrack()
выше).Пример:
onPeerTrack ( ( track , stream , peerId ) =>
console . log ( `got track from ${ peerId } ` , track )
)
makeAction(actionId)
Прослушивайте и отправляйте пользовательские действия с данными.
actionId
— строка для последовательной регистрации этого действия среди всех одноранговых узлов.Возвращает массив из трех функций:
Отправляет данные одноранговым узлам и возвращает обещание, которое выполняется, когда все целевые одноранговые узлы завершают получение данных.
(data, [targetPeers], [metadata], [onProgress])
data
— любое значение для отправки (примитивное, объектное, двоичное). Сериализация и фрагментирование выполняются автоматически. Двоичные данные (например, Blob
, TypedArray
) принимаются другим узлом как независимый ArrayBuffer
.
targetPeers
— (необязательно) Либо идентификатор узла (строка), массив идентификаторов узла, либо null
(указывает на отправку всем узлам в комнате).
metadata
— (необязательно) Если данные двоичные, вы можете отправить дополнительный объект метаданных, описывающий их (см. Двоичные метаданные).
onProgress
— (необязательно) Функция обратного вызова, которая будет вызываться при передаче каждого фрагмента для каждого узла. Функция будет вызываться со значением от 0 до 1 и идентификатором узла. Пример см. в разделе Обновления хода выполнения.
Регистрирует функцию обратного вызова, которая запускается при получении данных для этого действия от других узлов.
(data, peerId, metadata)
data
— значение, передаваемое отправляющим узлом. Десериализация осуществляется автоматически, т.е. число будет получено как число, объект как объект и т.д.
peerId
— строка идентификатора отправляющего узла.
metadata
— (необязательно) Необязательный объект метаданных, предоставляемый отправителем, если data
являются двоичными, например имя файла.
Регистрирует функцию обратного вызова, которая запускается при получении частичных данных от одноранговых узлов. Вы можете использовать это для отслеживания больших двоичных передач. Пример см. в разделе Обновления хода выполнения.
(percent, peerId, metadata)
percent
— число от 0 до 1, указывающее процент завершения передачи.
peerId
— строка идентификатора отправляющего узла.
metadata
— (необязательно) Необязательный объект метаданных, предоставленный отправителем.
Пример:
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)
Принимает идентификатор узла и возвращает обещание, которое выражается в миллисекундах, затраченных на путь туда и обратно до этого узла. Используйте это для измерения задержки.
peerId
— строка идентификатора узла целевого узла.Пример:
// log round-trip time every 2 seconds
room . onPeerJoin ( peerId =>
setInterval (
async ( ) => console . log ( `took ${ await room . ping ( peerId ) } ms` ) ,
2000
)
)
selfId
Уникальная строка идентификатора, которую другие узлы будут знать о локальном пользователе во всех комнатах.
getRelaySockets()
(только ? BitTorrent, ? Nostr, ? MQTT) Возвращает объект ключей URL-адреса ретранслятора, сопоставленных с их соединениями WebSocket. Это может быть полезно для определения состояния соединения пользователя с реле и обработки любых сбоев соединения.
Пример:
console . log ( trystero . getRelaySockets ( ) )
// => Object {
// "wss://tracker.webtorrent.dev": WebSocket,
// "wss://tracker.openwebtorrent.com": WebSocket
// }
getOccupants(config, roomId)
(Только для Firebase) Возвращает обещание, которое разрешается в список идентификаторов пользователей, присутствующих в данном пространстве имен. Это полезно для проверки количества пользователей в комнате, не присоединяясь к ней.
config
— объект конфигурацииroomId
— строка пространства имен, которую вы передаете в joinRoom()
.Пример:
console . log ( ( await trystero . getOccupants ( config , 'the_scope' ) ) . length )
// => 3
однократная установка¹ | размер комплекта² | пора подключаться³ | |
---|---|---|---|
? Ностр | никто ? | 54К | ⏱️⏱️ |
? MQTT | никто ? | 332 тыс. | ⏱️⏱️ |
? БитТоррент | никто ? | 25К? | ⏱️⏱️ |
⚡️ Супабаза | ~5 минут | 150 тыс. | ⏱️ ? |
Огневая база | ~5 минут | 177 тыс. | ⏱️ ? |
? ИПФС | никто ? | 945К | ⏱️⏱️ |
¹ Все стратегии, кроме Firebase, не требуют настройки. Firebase – это управляемая стратегия, требующая настройки учетной записи.
² Рассчитывается с помощью объединения Rollup + сжатия Terser.
³ Относительная скорость одноранговых узлов, подключающихся друг к другу при присоединении к комнате. Firebase работает практически мгновенно, в то время как другие стратегии немного медленнее обмениваются информацией о пиринге.
Уникальное преимущество trystero заключается в том, что он не требует настройки серверной части и в большинстве случаев использует децентрализованную инфраструктуру. Это позволяет проводить эксперименты без проблем и без единой точки отказа. Одним из потенциальных недостатков является то, что трудно гарантировать, что используемая общедоступная инфраструктура всегда будет высокодоступной, даже с использованием методов резервирования, которые использует trystero . В то время как другие стратегии децентрализованы, стратегии Supabase и Firebase представляют собой более управляемый подход с большим контролем и соглашением об уровне обслуживания, который может быть более подходящим для «производственных» приложений.
trystero упрощает переключение между стратегиями — просто измените одну строку импорта и быстро поэкспериментируйте:
import { joinRoom } from ' trystero /[torrent|nostr|mqtt|supabase|firebase|ipfs]'
trystero Дэна Мотценбекера