点对点 WebRTC 连接,内置信令与发现
Peer-to-peer WebRTC connections with built-in signaling and discovery

原始链接: https://github.com/lukks/like-webrtc

like-webrtc 是一个用于浏览器、Node.js 和 React Native 的点对点 WebRTC 库,内置信令和节点发现。它使用可共享的加密公钥而非 IP 地址,在设备和网络之间建立直接 P2P 连接。节点可以创建在公钥上监听的服务器,其他节点使用该地址连接。发现通过共享主题进行,包括 announce、lookup 和 join。它支持完整 WebRTC API,包括数据通道、音视频轨道和 transceiver,并预配置 STUN 和 TURN 服务器以及端到端 Noise 加密。默认包含 WebSocket 信令服务器。API 模仿 Node.js 模式(createServer、listen、connect),并包含 keyPair、randomBytes、WebStream 等辅助函数。还提供防火墙选项、断连重试和手动公告管理。采用 MIT 许可。

一篇 Hacker News 帖子介绍了用于点对点 WebRTC 连接的 GitHub 项目,内置信令与发现功能。它支持浏览器、Node.js 和 React Native,支持直接跨设备/网络连接、自动 SDP/ICE 协商、加密对等身份、基于主题的对等发现,以及标准 WebRTC 数据通道和媒体轨道。它可直接使用默认信令、STUN 和 TURN。评论询问它与 Trystero 的对比,并提到 Cloudflare 的免费 TURN/STUN 层级。帖子有 7 分和 3 条评论。
相关文章

原文

Peer-to-peer WebRTC connections with built-in signaling and peer discovery.

Works across browsers, Node.js, and React Native.

npm downloads license CI

  • P2P servers. Listen for peer connections anywhere, even in the browser.
  • Direct connections. Connect to peers across devices and networks.
  • Built-in signaling. Automatic SDP/ICE exchange and negotiation.
  • Identities. Shareable cryptographic addresses instead of IP addresses.
  • Peer discovery. Announce and find peers using shared topics.
  • WebRTC API. Use data channels, audio/video tracks and transceivers.
  • Ready to use. Signaling, STUN and TURN configured by default.

Live demo: https://web.leet.ar (P2P Discord clone built in 48 hours)

Need support with WebRTC? Open a GitHub issue :)

Direct peer-to-peer connections

A peer can create a server listening on a public key as address.

Another peer can use that address to connect to the server.

import RTC from 'like-webrtc'

const rtc = new RTC()

const server = rtc.createServer(peer => {
  const channel = peer.createDataChannel('wire', { negotiated: true, id: 0 })

  channel.addEventListener('open', () => channel.send('Hello from the server'))
  channel.addEventListener('message', e => console.log('Server received:', e.data))
})

const keyPair = RTC.keyPair()

await server.listen(keyPair)
const rtc2 = new RTC()

const peer = rtc2.connect(server.publicKey)

const channel = peer.createDataChannel('wire', { negotiated: true, id: 0 })

channel.addEventListener('open', () => channel.send('Hello from the client'))
channel.addEventListener('message', e => console.log('Client received:', e.data))

A familiar API like Node.js http, but peer-to-peer and running directly in your browser.

Click to see example

Peers can create servers with random key pairs.

You can announce or lookup any server under the same shared topic.

import RTC from 'like-webrtc'

const rtc = new RTC()

const server = rtc.createServer(peer => {
  console.log('New peer connection')
  // ...
})

await server.listen()
await server.announce('random-group')
const rtc2 = new RTC()

const results = await rtc2.lookup('random-group')

const peer = rtc2.connect(results[0].publicKey)
// ...
Click to see example

Each peer runs the same code to join the swarm.

Other peers will find you.

import RTC from 'like-webrtc'

const rtc = new RTC()

const server = rtc.createServer(peer => {
  console.log('New swarm connection')
  // ...
})

await server.listen()
await server.join('random-swarm')

Single signaling server:

  • wss://party.leet.ar:41337

It's a WebSocket server with a RPC protocol.

  • E2E noise encryption: meaning HTTPS/WSS is redundant.
  • Announce / Unannounce: act as a server e.g. listen/close.
  • Lookup: act as a client by finding peers.
  • Relay: bidirectional data for WebRTC SDP/ICE/ACK.

3 STUN servers:

  • stun:turn.leet.ar:3478
  • stun:stun.l.google.com:19302
  • stun:stun.cloudflare.com:3478

1 TURN server with multiple transports:

  • turn:turn.leet.ar:3478?transport=udp
  • turn:turn.leet.ar:3478?transport=tcp

Creates a WebRTC instance.

Options:

{
  signaling, // Defaults to 'wss://party.leet.ar:41337'.
  keyPair, // Defaults to a key pair generated from seed or random bytes.
  seed, // Seed used to generate the key pair.
  iceServers, // Defaults to the package's STUN and TURN servers.
  iceTransportPolicy, // Defaults to 'all'.
  trickle, // Defaults to true.
  RTCPeerConnection, // Optional WebRTC implementation override.
  RTCIceCandidate // Optional ICE candidate implementation override.
}

peer = rtc.connect(publicKey[, options])

Creates a P2P connection and returns a RTCPeerConnection.

Add a data channel, track, or transceiver to begin WebRTC negotiation.

Options:

{
  keyPair // Defaults to rtc.keyPair.
}

Identifies the client (true) or server (false) side.

The local public key used for this connection as a buffer.

The local public key used for this connection as a Base58 string.

The remote peer's public key as a buffer.

server = rtc.createServer([options][, handler])

Creates a P2P server that accepts WebRTC connections.

The handler receives each incoming peer connection.

Options:

{
  keyPair, // Defaults to rtc.keyPair.
  firewall // Function or array of allowed public keys. Allows all peers by default.
}

server.on('connection', peer)

Emitted on each incoming RTCPeerConnection, same as the handler.

Returns the server's public key as a buffer.

Returns the server's public key as a Base58 string.

await server.listen([keyPair])

Starts listening for connections under the server's public key so peers can connect.

await server.announce(topic)

Announces the listening server under topic and refreshes the announcement while the server listens.

The server removes the announcement when it closes.

await server.unannounce(topic)

Removes the server's announcement for topic.

The server keeps listening for direct connections.

If the server has joined topic, it will keep looking up peers.

The topic stays unannounced until you call server.announce(topic) or leave and join again.

Finds peers that announce topic and connects to them.

If the server is listening, it also announces itself under that topic.

The server emits a connection event for each discovered connection.

Closed connections are retried after 1 second, 5 seconds, 15 seconds, then every 10 minutes.

await server.leave(topic)

Stops finding peers under topic.

If only server.join(topic) announced the topic, it also removes that announcement.

An announcement made from server.announce(topic) stays active.

Existing peer connections stay open.

Cancels retries unless the peer was also discovered under another joined topic.

Closes the server's peer connections, removes its topic announcements, and closes its signaling connection.

await rtc.announce(topic[, options])

Signs and sends the announcement with keyPair.

Options:

{
  keyPair // Defaults to rtc.keyPair.
}

The announcement expires unless you refresh or remove it.

await rtc.unannounce(topic[, options])

Signs and sends a request to remove the announcement with keyPair.

Options:

{
  keyPair // Defaults to rtc.keyPair.
}

peers = await rtc.lookup(topic)

Returns peers announced under topic:

An announcement can remain even after a peer abruptly disconnects, unless closed properly.

The peer can stay discoverable while reconnecting after a brief signaling drop or page refresh.

A lookup during this gap can return a peer that is still offline.

Closes the RTC instance, its servers, its peers, and its signaling.

If you called rtc.announce() directly, call rtc.unannounce() to remove those announcements.

If you do not remove these manual announcements, they remain available until expiration.

keyPair = RTC.keyPair([seed])

Creates a key pair. Pass seed to create the same key pair each time.

bytes = RTC.randomBytes(size)

Returns random bytes.

stream = RTC.WebStream(dataChannelOrWebSocket)

Wraps a WebRTC data channel or a WebSocket in a duplex stream.

Useful for interacting with common Node.js streams.

WhatsApp relays and stores messages for 30d if the recipient is offline.

Telegram uses WebRTC with double encryption to avoid trusting SRTP/DTLS.

Discord forwards WebRTC media with SFUs so peers don't connect together.

like-webrtc can do the same for a perfect P2P experience including the browser.

  • RPC relay messages must be E2E encrypted between peers to avoid learning from connections or metadata
  • Create a tiny SFU topology from scratch using WebRTC e.g. 3 people speaking and 3000 listening
  • Signaling could be a HTTPS server with EventSource/SSE instead of a WebSocket server
  • Make deploying TURN servers easy so people can use their own and allow app creators to pay for bandwidth
  • Payments is outside of the scope of this module but it's important for peers to be able to exchange value
  • More cryptographic safety around verifying announcement signatures locally
  • WebRTC-HTTP ingestion protocol (WHIP instead of RTMP?)
  • WebRTC-HTTP egress protocol (WHEP instead of HLS/CDN?)
  • Reusable module for WebRTC audio, video, screen, etc so that creating frontend apps is easy
  • HTTPS server that helps connect to a WebRTC signaling peer to avoid TCP/HTTPS/WebSocket traffic

MIT. Copyright (c) Lucas Barrena

联系我们 contact @ memedata.com