-
Notifications
You must be signed in to change notification settings - Fork 29.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
quic: start adding in the internal quic js api
While the external API for QUIC is expected to be the WebTransport API primarily, this provides the internal API for QUIC that aligns with the native C++ QUIC components.
- Loading branch information
Showing
9 changed files
with
2,348 additions
and
69 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
'use strict'; | ||
|
||
const { | ||
Uint8Array, | ||
} = primordials; | ||
|
||
const { | ||
ReadableStream, | ||
} = require('internal/webstreams/readablestream'); | ||
|
||
const { | ||
WritableStream, | ||
} = require('internal/webstreams/writablestream'); | ||
|
||
const { | ||
isArrayBufferView, | ||
} = require('util/types'); | ||
|
||
const { | ||
codes: { | ||
ERR_INVALID_ARG_TYPE, | ||
}, | ||
} = require('internal/errors'); | ||
|
||
// QUIC datagrams are unordered, unreliable packets of data exchanged over | ||
// a session. They are unrelated to any specific QUIC stream. Our implementation | ||
// uses a ReadableStream to receive datagrams and a WritableStream to send them. | ||
// Any ArrayBufferView can be used when sending a datagram. Received datagrams | ||
// will always be Uint8Array. | ||
// The DatagramReadableStream and DatagramWritableStream instances are created | ||
// and held internally by the QUIC Session object. Only the readable and writable | ||
// properties will be exposed. | ||
|
||
class DatagramReadableStream { | ||
#readable = undefined; | ||
|
||
/** @type {ReadableStreamDefaultController} */ | ||
#controller = undefined; | ||
|
||
constructor() { | ||
let controller; | ||
this.#readable = new ReadableStream({ | ||
start(c) { controller = c; }, | ||
}); | ||
this.#controller = controller; | ||
} | ||
|
||
get readable() { return this.#readable; } | ||
|
||
// Close the ReadableStream. The underlying source will be closed. Any | ||
// datagrams already in the queue will be preserved and will be read. | ||
close() { | ||
this.#controller.close(); | ||
} | ||
|
||
// Errors the readable stream | ||
error(reason) { | ||
this.#controller.error(reason); | ||
} | ||
|
||
// Enqueue a datagram to be read by the stream. This will always be | ||
// a Uint8Array. | ||
enqueue(datagram) { | ||
this.#controller.enqueue(datagram); | ||
} | ||
} | ||
|
||
class DatagramWritableStream { | ||
#writable = undefined; | ||
/** @type {WritableStreamDefaultController} */ | ||
#controller = undefined; | ||
|
||
/** | ||
* @callback DatagramWrittenCallback | ||
* @param {Uint8Array} chunk | ||
* @returns {Promise<void>} | ||
*/ | ||
|
||
/** | ||
* @callback DatagramClosedCallback | ||
* @returns {Promise<void>} | ||
*/ | ||
|
||
/** | ||
* @callback DatagramAbortedCallback | ||
* @param {any} reason | ||
* @returns {Promise<void>} | ||
*/ | ||
|
||
/** | ||
* @param {DatagramWrittenCallback} written | ||
* @param {DatagramClosedCallback} closed | ||
* @param {DatagramAbortedCallback} aborted | ||
*/ | ||
constructor(written, closed, aborted) { | ||
let controller; | ||
this.#writable = new WritableStream({ | ||
start(c) { controller = c; }, | ||
async close(controller) { | ||
try { | ||
await closed(undefined); | ||
} catch (err) { | ||
controller.error(err); | ||
} | ||
}, | ||
async abort(reason) { | ||
try { | ||
await aborted(reason); | ||
} catch { | ||
// There's nothing to do in this case | ||
} | ||
}, | ||
async write(chunk, controller) { | ||
if (!isArrayBufferView(chunk)) { | ||
throw new ERR_INVALID_ARG_TYPE('chunk', ['ArrayBufferView'], chunk); | ||
} | ||
const { | ||
byteOffset, | ||
byteLength, | ||
} = chunk; | ||
chunk = new Uint8Array(chunk.buffer.transfer(), byteOffset, byteLength); | ||
try { | ||
await written(chunk); | ||
} catch (err) { | ||
controller.error(err); | ||
} | ||
}, | ||
}); | ||
this.#controller = controller; | ||
} | ||
|
||
get writable() { return this.#writable; } | ||
|
||
error(reason) { | ||
this.#controller.error(reason); | ||
} | ||
} | ||
|
||
module.exports = { | ||
DatagramReadableStream, | ||
DatagramWritableStream, | ||
}; |
Oops, something went wrong.