diff --git a/index.bs b/index.bs index 46c69712..4ef3e190 100644 --- a/index.bs +++ b/index.bs @@ -332,15 +332,118 @@ A [=WebTransport stream=] has the following signals: -# `WebTransportDatagramDuplexStream` Interface # {#duplex-stream} +# `WebTransportDatagramsWritable` Interface # {#datagram-writable} + +A WebTransportDatagramsWritable is a {{WritableStream}} providing outgoing streaming +features to [=send a datagram | send datagrams=]. + +
+[Exposed=(Window,Worker), SecureContext, Transferable]
+interface WebTransportDatagramsWritable : WritableStream {
+};
+
+ +## Internal slots ## {#datagram-writable-internal-slots} + +A {{WebTransportDatagramsWritable}} object has the following internal slot. + + + + + + + + + + +
Internal Slot + Description (non-normative) +
`[[OutgoingDatagramsQueue]]` + A queue of tuples of an outgoing datagram, a timestamp and a promise + which is resolved when the datagram is sent or discarded. +
+ + To create a + {{WebTransportDatagramsWritable}}, perform the following steps. + + 1. Let |stream| be a [=new=] {{WebTransportDatagramsWritable}}, with: + : {{[[OutgoingDatagramsQueue]]}} + :: an empty queue + 1. Return |stream|. + +## Procedures ## {#datagram-writable-procedures} + +
+ +The writeDatagrams algorithm is given a |transport| and |writable| as parameters and +|data| as input. It is defined by running the following steps: + +1. Let |timestamp| be a timestamp representing now. +1. If |data| is not a {{BufferSource}} object, then return [=a promise rejected with=] a {{TypeError}}. +1. Let |datagrams| be |transport|.{{[[Datagrams]]}}. +1. If |datagrams|.{{[[OutgoingMaxDatagramSize]]}} is less than |data|'s \[[ByteLength]], return + [=a promise resolved with=] undefined. +1. Let |promise| be a new promise. +1. Let |bytes| be a copy of bytes which |data| represents. +1. Let |chunk| be a tuple of |bytes|, |timestamp| and |promise|. +1. Enqueue |chunk| to |writable|.{{[[OutgoingDatagramsQueue]]}}. +1. If the length of |writable|.{{[[OutgoingDatagramsQueue]]}} is less than + |datagrams|.{{[[OutgoingDatagramsHighWaterMark]]}}, then [=resolve=] |promise| with undefined. +1. Return |promise|. + +Note: The associated {{WritableStream}} calls [=writeDatagrams=] only when all the promises that +have been returned by [=writeDatagrams=] for that stream have been resolved. Hence the +timestamp and the expiration duration work well only when the web developer pays attention to +{{WritableStreamDefaultWriter/ready|WritableStreamDefaultWriter.ready}}. + +
+ +
+ +To sendDatagrams, given a {{WebTransport}} object |transport| and a +{{WebTransportDatagramsWritable}} object |writable|, run these steps: +1. Let |queue| be |writable|.{{[[OutgoingDatagramsQueue]]}}. +1. Let |datagrams| be |transport|.{{[[Datagrams]]}}. +1. Let |duration| be |datagrams|.{{[[OutgoingDatagramsExpirationDuration]]}}. +1. If |duration| is null, then set |duration| to an [=implementation-defined=] value. +1. While |queue| is not empty: + 1. Let |bytes|, |timestamp| and |promise| be |queue|'s first element. + 1. If more than |duration| milliseconds have passed since |timestamp|, then: + 1. Remove the first element from |queue|. + 1. [=Queue a network task=] with |transport| to [=resolve=] |promise| with |undefined|. + 1. Otherwise, break this loop. +1. If |transport|.{{[[State]]}} is not `"connected"`, then return. +1. Let |maxSize| be |datagrams|.{{[[OutgoingMaxDatagramSize]]}}. +1. While |queue| is not empty: + 1. Let |bytes|, |timestamp| and |promise| be |queue|'s first element. + 1. If |bytes|'s length ≤ |maxSize|: + 1. If it is not possible to send |bytes| to the network immediately, then break this loop. + 1. [=session/Send a datagram=], with |transport|.{{[[Session]]}} and |bytes|. + 1. Remove the first element from |queue|. + 1. [=Queue a network task=] with |transport| to [=resolve=] |promise| with undefined. + +
+ +The user agent SHOULD run [=sendDatagrams=] for any {{WebTransport}} object whose +{{[[State]]}} is `"connecting"` or `"connected"` as soon as reasonably possible on each of +its associated {{WebTransportDatagramsWritable}} objects whenever the +algorithm can make progress. + +Note: Writing datagrams while the transport's {{[[State]]}} is `"connecting"` is allowed. The +datagrams are stored in {{[[OutgoingDatagramsQueue]]}}, and they can be discarded +in the same manner as when in the `"connected"` state. Once the transport's {{[[State]]}} becomes +`"connected"`, it will start sending the queued datagrams. + +# `WebTransportDatagramDuplexStream` Interface # {#datagram-duplex-stream} A WebTransportDatagramDuplexStream is a generic duplex stream.
 [Exposed=(Window,Worker), SecureContext]
 interface WebTransportDatagramDuplexStream {
+  WebTransportDatagramsWritable createWritable();
   readonly attribute ReadableStream readable;
-  readonly attribute WritableStream writable;
+  readonly attribute WebTransportDatagramsWritable writable;
 
   readonly attribute unsigned long maxDatagramSize;
   attribute unrestricted double? incomingMaxAge;
@@ -350,7 +453,7 @@ interface WebTransportDatagramDuplexStream {
 };
 
-## Internal slots ## {#datagramduplexstream-internal-slots} +## Internal slots ## {#datagram-duplex-stream-internal-slots} A {{WebTransportDatagramDuplexStream}} object has the following internal slots. @@ -368,7 +471,7 @@ A {{WebTransportDatagramDuplexStream}} object has the following internal slots. `[[Writable]]` - A {{WritableStream}} for outgoing datagrams. + A default {{WebTransportDatagramsWritable}} for outgoing datagrams. `[[IncomingDatagramsQueue]]` @@ -388,11 +491,6 @@ A {{WebTransportDatagramDuplexStream}} object has the following internal slots. An {{unrestricted double}} representing the expiration duration for incoming datagrams (in milliseconds), or null. - - `[[OutgoingDatagramsQueue]]` - A queue of tuples of an outgoing datagram, a timestamp and a promise - which is resolved when the datagram is sent or discarded. - `[[OutgoingDatagramsHighWaterMark]]` An {{unrestricted double}} representing the @@ -432,8 +530,6 @@ The user agent MAY update {{[[OutgoingMaxDatagramSize]]}} for any {{WebTransport :: an [=implementation-defined=] value : {{[[IncomingDatagramsExpirationDuration]]}} :: null - : {{[[OutgoingDatagramsQueue]]}} - :: an empty queue : {{[[OutgoingDatagramsHighWaterMark]]}} :: an [=implementation-defined=] value
@@ -446,6 +542,19 @@ The user agent MAY update {{[[OutgoingMaxDatagramSize]]}} for any {{WebTransport :: an [=implementation-defined=] integer. 1. Return |stream|. +## Methods ## {#datagram-duplex-stream-methods} + +: createWritable() + +:: Creates a {{WebTransportDatagramsWritable}}. + + When `createWritable()` method is called, the user agent MUST + run the following steps: + 1. Let |transport| be {{WebTransport}} object associated with [=this=]. + 1. If |transport|.{{[[State]]}} is `"closed"` or `"failed"`, + [=throw=] an {{InvalidStateError}}. + 1. Return the result of [=WebTransportDatagramsWritable/creating=] a {{WebTransportDatagramsWritable}}. + ## Attributes ## {#datagram-duplex-stream-attributes} : readable @@ -546,64 +655,6 @@ The user agent SHOULD run [=receiveDatagrams=] for any {{WebTransport}} object w {{[[State]]}} is `"connected"` as soon as reasonably possible whenever the algorithm can make progress. -
- -The writeDatagrams algorithm is given a |transport| as parameter and -|data| as input. It is defined by running the following steps: - -1. Let |timestamp| be a timestamp representing now. -1. If |data| is not a {{BufferSource}} object, then return [=a promise rejected with=] a {{TypeError}}. -1. Let |datagrams| be |transport|.{{[[Datagrams]]}}. -1. If |datagrams|.{{[[OutgoingMaxDatagramSize]]}} is less than |data|'s \[[ByteLength]], return - [=a promise resolved with=] undefined. -1. Let |promise| be a new promise. -1. Let |bytes| be a copy of bytes which |data| represents. -1. Let |chunk| be a tuple of |bytes|, |timestamp| and |promise|. -1. Enqueue |chunk| to |datagrams|.{{[[OutgoingDatagramsQueue]]}}. -1. If the length of |datagrams|.{{[[OutgoingDatagramsQueue]]}} is less than - |datagrams|.{{[[OutgoingDatagramsHighWaterMark]]}}, then [=resolve=] |promise| with undefined. -1. Return |promise|. - -Note: The associated {{WritableStream}} calls [=writeDatagrams=] only when all the promises that -have been returned by [=writeDatagrams=] have been resolved. Hence the timestamp and the expiration -duration work well only when the web developer pays attention to -{{WritableStreamDefaultWriter/ready|WritableStreamDefaultWriter.ready}}. - -
- -
- -To sendDatagrams, given a {{WebTransport}} object |transport|, run these steps: -1. Let |queue| be |datagrams|.{{[[OutgoingDatagramsQueue]]}}. -1. Let |duration| be |datagrams|.{{[[OutgoingDatagramsExpirationDuration]]}}. -1. If |duration| is null, then set |duration| to an [=implementation-defined=] value. -1. While |queue| is not empty: - 1. Let |bytes|, |timestamp| and |promise| be |queue|'s first element. - 1. If more than |duration| milliseconds have passed since |timestamp|, then: - 1. Remove the first element from |queue|. - 1. [=Queue a network task=] with |transport| to [=resolve=] |promise| with |undefined|. - 1. Otherwise, break this loop. -1. If |transport|.{{[[State]]}} is not `"connected"`, then return. -1. Let |maxSize| be |datagrams|.{{[[OutgoingMaxDatagramSize]]}}. -1. While |queue| is not empty: - 1. Let |bytes|, |timestamp| and |promise| be |queue|'s first element. - 1. If |bytes|'s length ≤ |maxSize|: - 1. If it is not possible to send |bytes| to the network immediately, then break this loop. - 1. [=session/Send a datagram=], with |transport|.{{[[Session]]}} and |bytes|. - 1. Remove the first element from |queue|. - 1. [=Queue a network task=] with |transport| to [=resolve=] |promise| with undefined. - -
- -The user agent SHOULD run [=sendDatagrams=] for any {{WebTransport}} object whose -{{[[State]]}} is `"connecting"` or `"connected"` as soon as reasonably possible whenever the -algorithm can make progress. - -Note: Writing datagrams while the transport's {{[[State]]}} is `"connecting"` is allowed. The -datagrams are stored in {{[[OutgoingDatagramsQueue]]}}, and they can be discarded -in the same manner as when in the `"connected"` state. Once the transport's {{[[State]]}} becomes -`"connected"`, it will start sending the queued datagrams. - # `WebTransport` Interface # {#web-transport} `WebTransport` provides an API to the underlying transport functionality @@ -779,7 +830,8 @@ agent MUST run the following steps: 1. Let |anticipatedConcurrentIncomingBidirectionalStreams| be {{WebTransport/constructor(url, options)/options}}'s {{WebTransportOptions/anticipatedConcurrentIncomingBidirectionalStreams}}. 1. Let |incomingDatagrams| be a [=new=] {{ReadableStream}}. -1. Let |outgoingDatagrams| be a [=new=] {{WritableStream}}. +1. Let |outgoingDatagrams| be a the result of [=WebTransportDatagramsWritable/creating=] a + {{WebTransportDatagramsWritable}} with |transport|. 1. Let |datagrams| be the result of [=WebTransportDatagramDuplexStream/creating=] a {{WebTransportDatagramDuplexStream}}, its [=WebTransportDatagramDuplexStream/create/readable=] set to |incomingDatagrams| and its [=WebTransportDatagramDuplexStream/create/writable=] set to |outgoingDatagrams|.