@fails-components/webtransport
Version:
A component to add webtransport support (server and client) to node.js using libquiche
332 lines (308 loc) • 9.87 kB
JavaScript
// Copyright (c) 2022 Marten Richter or other contributers (see commit). All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @param {import('../lib/dom').WebTransport} session
*/
export async function incomingBidirectionalEchoTest(session) {
try {
const bidiReader = session.incomingBidirectionalStreams.getReader()
while (true) {
const bidistr = await bidiReader.read()
if (bidistr.done) {
console.log('bidiReader terminated')
break
}
if (bidistr.value) {
// ok we got a stream
const bidistream = bidistr.value
// echo it
await bidistream.readable.pipeTo(bidistream.writable)
console.log('bidiReader finished piping')
}
}
} catch (error) {
console.log('incoming bidiReader exited with', error)
}
}
/**
* @param {import('../lib/dom').WebTransport} session
*/
export async function outgoingBidirectionalEchoTest(session) {
try {
const mybidistream = await session.createBidirectionalStream()
await mybidistream.readable.pipeTo(mybidistream.writable)
} catch (error) {
console.log('outgoing bidiReader exited with', error)
}
}
/**
* @param {import('../lib/dom').WebTransport} session
*/
export async function unidirectionalEchoTest(session) {
try {
const unidiReader = session.incomingUnidirectionalStreams.getReader()
while (true) {
const unidistr = await unidiReader.read()
if (unidistr.done) {
console.log('unidiReader terminated')
break
}
if (unidistr.value) {
// ok we got a stream
const unidistream = unidistr.value
// echo it
const uniwritable = await session.createUnidirectionalStream()
await unidistream.pipeTo(uniwritable)
console.log('unidiReader finished piping')
}
}
} catch (error) {
console.log('unidiReader exited with', error)
}
}
/**
* @param {import('../lib/dom').WebTransport} session
*/
export async function datagramEchoTest(session) {
try {
const writable =
session.datagrams.writable || session.datagrams.createWritable()
session.datagrams.readable.pipeTo(writable)
} catch (error) {
console.log('datagram echo exited with', error)
}
}
/**
* @param {import('../lib').Http3Server|import('../lib').Http2Server} server
*/
export async function runEchoServer(server) {
try {
const sessionStream = await server.sessionStream('/echo')
const sessionReader = sessionStream.getReader()
while (true) {
const { done, value } = await sessionReader.read()
if (done) {
console.log('Server is gone')
break
}
console.log('got a newsession')
await value.ready
console.log('server session is ready')
const helpfunc = async () => {
try {
const err = await value.closed
console.log('server session was closed', err)
} catch (error) {
console.log('server session close error:', error)
}
}
helpfunc()
// install BidirectionalEchoTest
incomingBidirectionalEchoTest(value)
// now send a bidirectional stream out
outgoingBidirectionalEchoTest(value)
unidirectionalEchoTest(value)
console.log('install datagram echo')
datagramEchoTest(value)
}
} catch (error) {
console.log('problem in runEchoServer', error)
}
}
/**
* @param {ArrayLike<any>} array1
* @param {ArrayLike<any>} array2
*/
function testArraysEqual(array1, array2) {
if (array1.length !== array2.length)
throw new Error('Array not equal in length')
for (let i = 0; i < array1.length; i++) {
if (array1[i] !== array2[i]) throw new Error('Array not equal in value')
}
}
/**
* @param {import('../lib/dom').WebTransport} transport
*/
export async function echoTestsConnection(transport) {
// some echo tests for testing the webtransport library, not for production
const stream = await transport.createBidirectionalStream()
const writer = stream.writable.getWriter()
const data1 = new Uint8Array([65, 66, 67])
const data2 = new Uint8Array([68, 69, 70])
writer.write(data1)
writer.write(data2)
const reader = stream.readable.getReader()
let i = data1.length + data2.length
let pos = 0
const refArray1 = new Uint8Array(i)
refArray1.set(data1)
refArray1.set(data2, data1.length)
const resultArray1 = new Uint8Array(i)
console.log('TEST 1: start')
while (i > 0) {
const { done, value } = await reader.read()
if (done) {
break
}
// value is a Uint8Array
console.log('incoming bidi stream', value, Date.now())
resultArray1.set(value, pos)
i -= value.length
pos += value.length
}
console.log('all bidi received, next close writer')
try {
await writer.close()
console.log('All data has been sent.')
} catch (error) {
console.error(`An error occurred: ${error}`)
throw new Error('outgoing bidi stream test failed')
}
console.log('next close reader')
try {
await reader.cancel(0)
console.log('All data has been read.')
} catch (error) {
console.error(`An error occurred: ${error}`)
throw new Error('outgoing bidi stream test failed')
}
testArraysEqual(refArray1, resultArray1)
console.log('webtransport sending bidistream success')
console.log('TEST 1: finish')
console.log('TEST 2: start')
const bidiReader = transport.incomingBidirectionalStreams.getReader()
const incombidi = await bidiReader.read()
if (incombidi.value) {
const bidistream = incombidi.value
console.log('got a bidistream')
const write = bidistream.writable.getWriter()
const data3 = new Uint8Array([71, 72, 73])
const data4 = new Uint8Array([74, 75, 76])
write.write(data3)
write.write(data4)
const readbd = bidistream.readable.getReader()
let i = data3.length + data4.length
let pos = 0
const refArray2 = new Uint8Array(i)
refArray2.set(data3)
refArray2.set(data4, data3.length)
const resultArray2 = new Uint8Array(i)
while (i > 0) {
const { done, value } = await readbd.read()
if (done) {
break
}
// value is a Uint8Array
console.log('incom bd', value, Date.now())
resultArray2.set(value, pos)
i -= value.length
pos += value.length
}
try {
await write.close()
console.log('All data has been sent for incoming bidi stream.')
} catch (error) {
console.error(`An error occurred: ${error}`)
throw new Error('incoming bidi stream test failed')
}
try {
await readbd.cancel(0)
console.log('All data has been read for incoming bidi stream.')
} catch (error) {
console.error(`An error occurred: ${error}`)
throw new Error('outgoing bidi stream test failed')
}
testArraysEqual(refArray2, resultArray2)
}
console.log('TEST 2: finish')
console.log('TEST 3: start')
console.log('now unidirectional tests')
const unidioutstream = await transport.createUnidirectionalStream()
const unidiwrite = unidioutstream.getWriter()
const data5 = new Uint8Array([77, 78, 79])
const data6 = new Uint8Array([80, 81, 82])
unidiwrite.write(data5)
unidiwrite.write(data6)
const unidiReader = transport.incomingUnidirectionalStreams.getReader()
const incomunidi = await unidiReader.read()
i = data5.length + data6.length
const refArray3 = new Uint8Array(i)
refArray3.set(data5)
refArray3.set(data6, data5.length)
let readud
if (incomunidi.value) {
const unidistream = incomunidi.value
console.log('got a unidistream')
readud = unidistream.getReader()
let pos = 0
const resultArray3 = new Uint8Array(i)
while (i > 0) {
const { done, value } = await readud.read()
if (done) {
break
}
// value is a Uint8Array
console.log('incom ud', value, Date.now())
resultArray3.set(value, pos)
i -= value.length
pos += value.length
}
testArraysEqual(refArray3, resultArray3)
}
try {
await unidiwrite.close()
console.log('All data has been sent for incoming unidi stream.')
} catch (error) {
console.error(`An error occurred: ${error}`)
throw new Error('incoming unidi stream test failed')
}
if (readud) {
try {
await readud.cancel(0)
console.log('All data has been read for incoming unidi stream.')
} catch (error) {
console.error(`An error occurred: ${error}`)
throw new Error('incoming unidi stream test failed')
}
}
console.log('TEST 3: finish')
console.log('TEST 4: start')
console.log('finally test datagrams')
const dwritable =
transport.datagrams.writable || transport.datagrams.createWritable()
const datawrite = await dwritable.getWriter()
const data7 = new Uint8Array([83, 84, 85])
const data8 = new Uint8Array([86, 87, 88])
i = data7.length + data8.length
const refArray4 = new Uint8Array(i)
refArray4.set(data7)
refArray4.set(data8, data7.length)
datawrite.write(data7)
datawrite.write(data8)
const readdg = await transport.datagrams.readable.getReader()
pos = 0
const resultArray4 = new Uint8Array(i)
while (i > 0) {
const { done, value } = await readdg.read()
if (done) {
break
}
// value is a Uint8Array
console.log('incom dg', value, Date.now())
resultArray4.set(value, pos)
i -= value.length
pos += value.length
}
testArraysEqual(refArray4, resultArray4)
try {
await datawrite.close()
console.log('All data has been sent for datagram stream.')
} catch (error) {
console.error(`An error occurred: ${error}`)
throw new Error('datagram stream test failed')
}
console.log('test datagrams finished')
console.log('TEST 4: finish')
console.log('start close stream tests')
}