서버가 필요 없는 인스턴트 멀티플레이어 웹 앱 구축
데모를 사용해 보시겠습니까 ?
trystero 애플리케이션 사용자가 서버 중개자 없이 암호화되어 서로 직접 대화할 수 있는 비밀 택배 네트워크를 관리합니다.
인터넷은 토렌트 추적기, IoT 장치 브로커, 부티크 파일 프로토콜, 틈새 소셜 네트워크 등 개방적이고 분산된 통신 채널로 가득 차 있습니다.
trystero 이러한 네트워크에 편승하여 귀하의 노력 없이도 앱 사용자 간에 안전한 비공개 p2p 연결을 자동으로 설정합니다.
피어는 ?를 통해 연결할 수 있습니다. 비트토렌트, ? 노스트르, ? MQTT, ⚡️ Supabase, Firebase 또는 ? IPFS – 모두 동일한 API를 사용합니다.
피어 매칭을 자동으로 만드는 것 외에도 trystero WebRTC 위에 몇 가지 멋진 추상화를 제공합니다.
여기에서 사람들이 trystero 사용하여 무엇을 만들고 있는지 볼 수 있습니다.
trystero 시험해보고 싶다면 이 설명을 건너뛰고 곧바로 사용해 볼 수 있습니다.
WebRTC와 직접 P2P 연결을 설정하려면 피어 정보(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)
다음으로, ID가 있는 방에 사용자를 참여시킵니다.
const config = { appId : 'san_narciso_3d' }
const room = joinRoom ( config , 'yoyodyne' )
첫 번째 인수는 appId
필요한 구성 객체입니다. 이는 앱에 대한 완전히 고유한 식별자여야 합니다¹. 두 번째 인수는 방 ID입니다.
왜 방인가? 브라우저는 한 번에 제한된 양의 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
가져와서 로컬 사용자의 피어 ID에 액세스할 수 있습니다.
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 사이의 백분율 값과 수신 피어의 ID로 호출됩니다.
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 } `
)
)
모든 메타데이터는 진행 이벤트와 함께 전송되므로 수신 파일 이름과 함께 전송이 진행 중임을 수신 사용자에게 보여줄 수 있습니다.
피어는 여러 전송을 동시에 보낼 수 있으므로 메타데이터를 사용하여 고유 ID를 보내는 등의 방식으로 이를 구별할 수도 있습니다.
피어가 서로 연결되면 모든 통신이 종단 간 암호화됩니다. 초기 연결/검색 프로세스 중에 피어의 SDP는 선택한 피어링 전략 매체를 통해 전송됩니다. 기본적으로 SDP는 일반 텍스트 세션 데이터가 로그에 표시되는 것을 방지하기 위해 앱 ID 및 방 ID에서 파생된 키를 사용하여 암호화됩니다. 이는 대부분의 사용 사례에 적합하지만 릴레이 전략 운영자는 회의실 및 앱 ID를 사용하여 키를 리버스 엔지니어링할 수 있습니다. 보다 안전한 옵션은 암호화 키를 파생하는 데 사용되는 앱 구성 개체에 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 >
</ >
)
}
기민한 독자라면 위의 예가 간단하고 구성 요소의 룸 ID를 변경하거나 마운트 해제할지 여부를 고려하지 않는다는 것을 알 수 있습니다. 이러한 시나리오의 경우 룸 이벤트 구독을 취소하는 간단한 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
로 설정하고, anon public
API 키를 복사하여 trystero 구성에서 supabaseKey
로 설정합니다.Firebase 전략을 사용하고 싶지만 기존 프로젝트가 없는 경우:
databaseURL
복사하여 trystero 구성에서 appId
로 사용하세요.{
"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를 사용하는 경우 이는 Firebase 구성의 databaseURL
이어야 합니다. Firebase 전략을 구성하는 다른 방법은 아래의 firebaseApp
도 참조하세요.
password
- (선택 사항) 피어링 매체를 통해 전달될 때 AES-GCM을 통해 세션 설명을 암호화하는 문자열입니다. 설정하지 않으면 세션 설명이 앱 ID와 방 이름에서 파생된 키로 암호화됩니다. 연결하려면 방에 있는 모든 피어 간에 사용자 지정 비밀번호가 일치해야 합니다. 자세한 내용은 암호화를 참조하세요.
rtcConfig
- (선택 사항) 모든 피어 연결에 대한 사용자 정의 RTCConfiguration
지정합니다.
relayUrls
- (선택 사항, ? BitTorrent, ? Nostr, ? MQTT에만 해당) P2P 연결을 부트스트랩하는 데 사용할 전략에 대한 사용자 정의 URL 목록입니다. 이들은 각각 BitTorrent 추적기, Nostr 릴레이 및 MQTT 브로커입니다. 보안 WebSocket 연결을 지원해야 합니다.
relayRedundancy
- (선택 사항, ? BitTorrent, ? Nostr, ? MQTT에만 해당) 일부 토렌트 추적기가 실패할 경우 동시에 연결할 토렌트 추적기 수를 지정하는 정수입니다. relayUrls
옵션을 전달하면 전체 목록이 사용되므로 이 옵션이 무시됩니다.
supabaseKey
- (필수, ⚡️ Supabase만 해당) Supabase 프로젝트의 anon public
API 키입니다.
firebaseApp
- (선택사항, Firebase에만 해당) appId
대신 이미 초기화된 Firebase 앱 인스턴스를 전달할 수 있습니다. 일반적으로 trystero appId
기반으로 Firebase 앱을 초기화하지만 다른 곳에서 사용하기 위해 이미 초기화한 경우에는 실패합니다.
rootPath
- (선택 사항, Firebase에만 해당) trystero 데이터베이스에 매치메이킹 데이터를 쓰는 경로를 지정하는 문자열입니다(기본적으로 '__ trystero __'
). 이를 변경하면 동일한 데이터베이스를 사용하여 여러 앱을 실행하고 네임스페이스 충돌을 걱정하지 않으려는 경우 유용합니다.
libp2pConfig
- (선택 사항, ? IPFS에만 해당) 부트스트래핑을 위한 정적 피어 목록을 지정할 수 있는 Libp2pOptions
입니다.
roomId
- 룸 내의 피어 및 이벤트에 네임스페이스를 지정하는 문자열입니다.
onError(details)
- (선택 사항) 잘못된 비밀번호로 인해 방에 참여할 수 없는 경우 호출되는 콜백 함수입니다. details
은 appId
, roomId
, peerId
및 error
를 설명하는 오류를 포함하는 객체입니다.
다음 메소드를 사용하여 객체를 반환합니다.
leave()
룸에서 로컬 사용자를 제거하고 룸 이벤트 구독을 취소합니다.
getPeers()
방에 있는 피어에 대한 RTCPeerConnection
맵을 반환합니다(로컬 사용자는 포함하지 않음). 이 객체의 키는 해당 피어의 ID입니다.
addStream(stream, [targetPeers], [metadata])
미디어 스트림을 다른 피어에게 브로드캐스트합니다.
stream
- 방에 있는 동료에게 보낼 오디오 및/또는 비디오가 포함된 MediaStream
입니다.
targetPeers
- (선택 사항) 지정된 경우 스트림은 대상 피어 ID(문자열) 또는 피어 ID 목록(배열)에만 전송됩니다.
metadata
- (선택 사항) 스트림과 함께 전송될 추가 메타데이터(직렬화 가능한 모든 유형)입니다. 이는 수신자가 어느 스트림인지 알 수 있도록 여러 스트림을 보낼 때 유용합니다(예: 웹캠 대 화면 캡처). 메타데이터 인수를 사용하여 방에 있는 모든 피어에게 스트림을 브로드캐스팅하려면 null
두 번째 인수로 전달합니다.
removeStream(stream, [targetPeers])
이전에 전송된 미디어 스트림을 다른 피어로 보내는 것을 중지합니다.
stream
- 전송을 중지하기 위해 이전에 전송된 MediaStream
입니다.
targetPeers
- (선택 사항) 지정된 경우 대상 피어 ID(문자열) 또는 피어 ID 목록(배열)에서만 스트림이 제거됩니다.
addTrack(track, stream, [targetPeers], [metadata])
스트림에 새 미디어 트랙을 추가합니다.
track
- 기존 스트림에 추가할 MediaStreamTrack
.
stream
- 새 트랙을 첨부할 대상 MediaStream
.
targetPeers
- (선택 사항) 지정된 경우 트랙은 대상 피어 ID(문자열) 또는 피어 ID 목록(배열)에만 전송됩니다.
metadata
- (선택 사항) 트랙과 함께 전송될 추가 메타데이터(직렬화 가능한 모든 유형)입니다. 자세한 내용은 위의 addStream()
에 대한 metadata
참고 사항을 참조하세요.
removeTrack(track, stream, [targetPeers])
스트림에서 미디어 트랙을 제거합니다.
track
- 제거할 MediaStreamTrack
.
stream
- 트랙이 첨부된 MediaStream
입니다.
targetPeers
- (선택 사항) 지정된 경우 대상 피어 ID(문자열) 또는 피어 ID 목록(배열)에서만 트랙이 제거됩니다.
replaceTrack(oldTrack, newTrack, stream, [targetPeers])
미디어 트랙을 새 트랙으로 교체합니다.
oldTrack
- 제거할 MediaStreamTrack
.
newTrack
- 연결할 MediaStreamTrack
입니다.
stream
- oldTrack
이 첨부된 MediaStream
.
targetPeers
- (선택 사항) 지정된 경우 대상 피어 ID(문자열) 또는 피어 ID 목록(배열)에 대해서만 트랙이 대체됩니다.
onPeerJoin(callback)
피어가 룸에 참가할 때 호출될 콜백 함수를 등록합니다. 두 번 이상 호출되면 가장 최근에 등록된 콜백만 호출됩니다.
callback(peerId)
- 피어가 참가할 때마다 실행되는 함수로, 피어의 ID로 호출됩니다.예:
onPeerJoin ( peerId => console . log ( ` ${ peerId } joined` ) )
onPeerLeave(callback)
상대방이 방을 나갈 때 호출될 콜백 함수를 등록합니다. 두 번 이상 호출되면 가장 최근에 등록된 콜백만 호출됩니다.
callback(peerId)
- 피어가 떠날 때마다 실행되는 함수로, 피어의 ID로 호출됩니다.예:
onPeerLeave ( peerId => console . log ( ` ${ peerId } left` ) )
onPeerStream(callback)
피어가 미디어 스트림을 보낼 때 호출될 콜백 함수를 등록합니다. 두 번 이상 호출되면 가장 최근에 등록된 콜백만 호출됩니다.
callback(stream, peerId, metadata)
- 피어가 미디어 스트림을 보낼 때마다 실행되는 함수로, 피어의 스트림, ID 및 선택적 메타데이터로 호출됩니다(자세한 내용은 위의 addStream()
참조).예:
onPeerStream ( ( stream , peerId ) =>
console . log ( `got stream from ${ peerId } ` , stream )
)
onPeerTrack(callback)
피어가 미디어 트랙을 보낼 때 호출될 콜백 함수를 등록합니다. 두 번 이상 호출되면 가장 최근에 등록된 콜백만 호출됩니다.
callback(track, stream, peerId, metadata)
- 피어가 미디어 트랙을 보낼 때마다 실행되는 함수입니다. 피어의 트랙, 첨부된 스트림, ID 및 선택적 메타데이터로 호출됩니다(자세한 내용은 위의 addTrack()
참조).예:
onPeerTrack ( ( track , stream , peerId ) =>
console . log ( `got track from ${ peerId } ` , track )
)
makeAction(actionId)
사용자 정의 데이터 작업을 수신하고 보냅니다.
actionId
- 모든 피어 간에 이 작업을 일관되게 등록하기 위한 문자열입니다.세 가지 함수의 배열을 반환합니다.
피어에게 데이터를 보내고 모든 대상 피어가 데이터 수신을 완료하면 확인하는 약속을 반환합니다.
(data, [targetPeers], [metadata], [onProgress])
data
- 전송할 모든 값(기본, 객체, 바이너리). 직렬화 및 청킹은 자동으로 처리됩니다. 바이너리 데이터(예: Blob
, TypedArray
)는 다른 피어에 의해 불가지론적인 ArrayBuffer
로 수신됩니다.
targetPeers
- (선택 사항) 피어 ID(문자열), 피어 ID 배열 또는 null
(방에 있는 모든 피어에게 전송함을 나타냄)입니다.
metadata
- (선택 사항) 데이터가 바이너리인 경우 이를 설명하는 선택적 메타데이터 개체를 보낼 수 있습니다(바이너리 메타데이터 참조).
onProgress
- (선택 사항) 모든 피어의 모든 청크가 전송될 때 호출되는 콜백 함수입니다. 함수는 0과 1 사이의 값과 피어 ID를 사용하여 호출됩니다. 예를 보려면 진행 상황 업데이트를 참조하세요.
이 작업에 대한 데이터가 다른 피어로부터 수신될 때 실행되는 콜백 함수를 등록합니다.
(data, peerId, metadata)
data
- 송신 피어가 전송한 값입니다. 역직렬화는 자동으로 처리됩니다. 즉, 숫자는 숫자로, 객체는 객체로 수신됩니다.
peerId
- 송신 피어의 ID 문자열입니다.
metadata
- (선택 사항) data
바이너리(예: 파일 이름)인 경우 보낸 사람이 제공하는 선택적 메타데이터 개체입니다.
피어로부터 부분 데이터를 수신할 때 실행되는 콜백 함수를 등록합니다. 대규모 바이너리 전송을 추적하는 데 이를 사용할 수 있습니다. 예를 보려면 진행 상황 업데이트를 참조하세요.
(percent, peerId, metadata)
percent
- 전송 완료율을 나타내는 0에서 1 사이의 숫자입니다.
peerId
- 송신 피어의 ID 문자열입니다.
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)
피어 ID를 가져와 해당 피어로의 왕복에 걸린 시간을 밀리초로 확인하는 약속을 반환합니다. 대기 시간을 측정하는 데 사용합니다.
peerId
- 대상 피어의 피어 ID 문자열입니다.예:
// log round-trip time every 2 seconds
room . onPeerJoin ( peerId =>
setInterval (
async ( ) => console . log ( `took ${ await room . ping ( peerId ) } ms` ) ,
2000
)
)
selfId
다른 피어가 로컬 사용자를 방 전체에 걸쳐 전역적으로 알 수 있는 고유 ID 문자열입니다.
getRelaySockets()
(? BitTorrent, ? Nostr, ? MQTT만 해당) WebSocket 연결에 매핑된 릴레이 URL 키의 개체를 반환합니다. 이는 사용자의 릴레이 연결 상태를 확인하고 연결 실패를 처리하는 데 유용할 수 있습니다.
예:
console . log ( trystero . getRelaySockets ( ) )
// => Object {
// "wss://tracker.webtorrent.dev": WebSocket,
// "wss://tracker.openwebtorrent.com": WebSocket
// }
getOccupants(config, roomId)
(Firebase만 해당) 지정된 네임스페이스에 있는 사용자 ID 목록으로 확인되는 Promise를 반환합니다. 이는 방에 참여하지 않고 방에 몇 명의 사용자가 있는지 확인하는 데 유용합니다.
config
- 구성 객체roomId
- joinRoom()
에 전달할 네임스페이스 문자열입니다.예:
console . log ( ( await trystero . getOccupants ( config , 'the_scope' ) ) . length )
// => 3
일회성 설정¹ | 번들 크기² | 연결할 시간 ³ | |
---|---|---|---|
? 노스트르 | 없음 ? | 54K | ⏱️⏱️ |
? MQTT | 없음 ? | 332K | ⏱️⏱️ |
? 비트토렌트 | 없음 ? | 25K? | ⏱️⏱️ |
⚡️ 수파베이스 | ~5분 | 150K | ⏱️ ? |
중포 기지 | ~5분 | 177K | ⏱️ ? |
? IPFS | 없음 ? | 945K | ⏱️⏱️ |
¹ Firebase를 제외한 모든 전략에는 설정이 필요하지 않습니다. Firebase는 계정 설정이 필요한 관리형 전략입니다.
² 롤업 번들링 + Terser 압축을 통해 계산됩니다.
³ 룸에 참여할 때 피어가 서로 연결하는 상대적 속도입니다. Firebase는 거의 즉각적이지만 다른 전략은 피어링 정보를 교환하는 데 약간 느립니다.
trystero 의 고유한 장점은 백엔드 설정이 필요하지 않으며 대부분의 경우 분산형 인프라를 사용한다는 것입니다. 이를 통해 마찰 없는 실험과 단일 실패 지점이 발생하지 않습니다. 한 가지 잠재적인 단점은 trystero 사용하는 중복 기술을 사용하더라도 사용하는 공공 인프라가 항상 높은 가용성을 보장하기 어렵다는 것입니다. 다른 전략은 분산되어 있지만 Supabase 및 Firebase 전략은 더 강력한 제어 기능과 SLA를 갖춘 관리형 접근 방식이므로 '프로덕션' 앱에 더 적합할 수 있습니다.
trystero 하면 전략 간 전환이 간단해집니다. 단일 가져오기 라인을 변경하고 빠르게 실험해 보세요.
import { joinRoom } from ' trystero /[torrent|nostr|mqtt|supabase|firebase|ipfs]'
Dan Motzenbecker의 trystero