Skip to content

Instantly share code, notes, and snippets.

@achingbrain
Created September 20, 2023 06:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save achingbrain/607cc86e74cf9ab09f7bb5ab115d5686 to your computer and use it in GitHub Desktop.
Save achingbrain/607cc86e74cf9ab09f7bb5ab115d5686 to your computer and use it in GitHub Desktop.
lib-datachannel large byte transfer
const nodeDataChannel = require('node-datachannel')
// Log Level
// nodeDataChannel.initLogger("Debug")
// increase `messagesToSend` until `Peer2` no longer receives all of the messages
const messagesToSend = 5000
// the number of successfully sent messages
let messagesSent = 0
// the number of successfully received messages
let receivedMessages = 0
// if this many bytes of data has been buffered, wait for the send buffer to empty
const maxBufferedAmount = 1024 * 1024
// how many bytes to send in each message
const messageSize = 1024 * 64
// if true, the sender will wait for `.bufferedAmount` to be `0` before closing the channel
const drainBeforeClose = true
const peer1 = new nodeDataChannel.PeerConnection('Peer1', { iceServers: [] })
const peer2 = new nodeDataChannel.PeerConnection('Peer2', { iceServers: [] })
peer1.onLocalDescription((sdp, type) => {
peer2.setRemoteDescription(sdp, type)
})
peer1.onLocalCandidate((candidate, mid) => {
peer2.addRemoteCandidate(candidate, mid)
})
peer2.onLocalDescription((sdp, type) => {
peer1.setRemoteDescription(sdp, type)
})
peer2.onLocalCandidate((candidate, mid) => {
peer1.addRemoteCandidate(candidate, mid)
})
// necessary to stop dc from being garbage collected
let peer2Dc
peer2.onDataChannel((dc) => {
peer2Dc = dc
let lastMessageCount = 0
let lastInterval = Date.now()
const interval = setInterval(() => {
if (lastMessageCount !== receivedMessages) {
const messagesSentInInterval = receivedMessages - lastMessageCount
const mBytesPerSecond = calculateTransferSpeed(lastInterval, messagesSentInInterval)
lastInterval = Date.now()
lastMessageCount = receivedMessages
console.info(`Peer2 received ${receivedMessages}/${messagesToSend} messages at ${mBytesPerSecond} MB/s`)
}
}, 1000)
console.log('Peer2 Got DataChannel', dc.getLabel())
const start = Date.now()
dc.onMessage(() => {
receivedMessages++
if (receivedMessages === messagesToSend) {
const mBytesPerSecond = calculateTransferSpeed(start, receivedMessages)
console.log(`Peer2 received all ${messagesToSend} messages at ${mBytesPerSecond} MB/s`)
clearInterval(interval)
peer1.close()
peer2.close()
nodeDataChannel.cleanup()
}
})
dc.onClosed(() => {
peer2Dc = null
})
})
const dc = peer1.createDataChannel('test channel')
dc.onOpen(async () => {
for (let i = 0; i < messagesToSend; i++) {
try {
dc.sendMessageBinary(Uint8Array.from(new Array(messageSize).fill(0)))
messagesSent++
if (dc.bufferedAmount() > maxBufferedAmount) {
// wait for any buffered messages to be sent before sending more messages
await drain(dc)
}
} catch (err) {
console.error('error after sending', i, 'messages', err.message, 'buffered amount was', dc.bufferedAmount())
break
}
}
console.info(`Peer1 sent ${messagesSent} messages, buffered amount was`, dc.bufferedAmount())
if (drainBeforeClose && dc.bufferedAmount() > 0) {
console.info(`Peer1 drain channel, buffered amount was`, dc.bufferedAmount())
// wait for bufferedAmount to be 0
await drain(dc)
}
console.info(`Peer1 close channel, buffered amount was`, dc.bufferedAmount())
dc.close()
})
async function drain (dc) {
if (dc.bufferedAmount() === 0) {
return
}
dc.setBufferedAmountLowThreshold(0)
await new Promise((resolve) => {
dc.onBufferedAmountLow(() => {
resolve()
})
})
}
function calculateTransferSpeed (start, messagesSent) {
const timeTakenMs = Date.now() - start
const timeTakenS = timeTakenMs / 1000
const bytesTransferred = messagesSent * messageSize
const bytesPerSecond = bytesTransferred / timeTakenS
const mBytesPerSecond = bytesPerSecond / (1000 * 1000)
return mBytesPerSecond.toFixed(2)
}
{
"name": "webrtc-transfer",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node index.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"node-datachannel": "^0.4.3"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment