Rationale
DatagramTransport
only works for transports with a strict limitation of datagram's sizes. This doesn't work well for a revamp of e.g. RTCDataChannel
and WebSocket
which can transport messages of (virtually) arbitrary size. DatagramTransport
also does not allow to send datagrams/messages within particular streams. Therefore, I'd like to propose a couple of changes (depends and leans on #46).
Proposal
Boring boilerplate first:
interface UnidirectionalMessageStreamsTransport {
Promise<SendMessageStream> createSendMessageStream (optional SendMessageStreamParameters parameters);
ReadableStream<ReceiveMessageStream> receiveMessageStreams ();
};
interface BidirectionalMessageStreamsTransport {
Promise<BidirectionalMessageStream> createBidirectionalMessageStream ();
ReadableStream<BidirectionalMessageStream> receiveBidirectionalMessageStreams ();
};
[Exposed=Window]
interface BidirectionalMessageStream : WebTransportStream {
};
BidirectionalMessageStream includes OutgoingMessageStream;
BidirectionalMessageStream includes IncomingMessageStream;
interface SendMessageStream : WebTransportStream {
};
SendMessageStream includes OutgoingMessageStream;
interface ReceiveMessageStream : WebTransportStream {
};
ReceiveMessageStream includes IncomingMessageStream;
[Exposed=Window]
interface mixin OutgoingMessageStream {
readonly attribute WritableStream<OutgoingMessage> writable;
readonly attribute Promise<StreamAbortInfo> writingAborted;
void abortWriting (StreamAbortInfo abortInfo);
};
[Exposed=Window]
interface mixin IncomingMessageStream {
readonly attribute ReadableStream<IncomingMessage> readable;
readonly attribute Promise<StreamAbortInfo> readingAborted;
void abortReading (StreamAbortInfo abortInfo);
};
The interesting part comes with the definition of OutgoingMessage
and IncomingMessage
:
[Exposed=Window]
interface OutgoingMessage : WritableStream<Uint8Array> {
};
[Exposed=Window]
interface IncomingStream : ReadableStream<Uint8Array> {
};
Note: Abort reading/writing a message does not necessarily mean aborting the stream, but depending on the implementation, it might also abort the stream.
An alternative would be to use the body mixin:
[Exposed=Window]
interface OutgoingMessage : Body {
void abort (DOMString reason);
};
[Exposed=Window]
interface IncomingStream : Body {
void cancel (DOMString reason);
};
Example Use Case: RTCDataChannelStream
Now, these interfaces could be used to improve RTCDataChannel
in the following way:
partial interface RTCPeerConnection {
Promise<RTCDataChannelStream> createDataChannelStream (USVString label, optional RTCDataChannelInit dataChannelDict);
ReadableStream<RTCDataChannelStream> receiveDataChannelStream ();
}
[Exposed=Window]
interface RTCDataChannelStream {
<relevant fields from RTCDataChannel here>
};
RTCDataChannelStream includes BidirectionalMessageStream;
I'd imagine this would work similarly well for WebSocket
.
Discussion
Following this terminology, it would make sense to rename SendStream
to SendByteStream
, ReceiveStream
to ReceiveByteStream
, OutgoingStream
to OutgoingByteStream
, IncomingStream
to IncomingByteStream
, SendStreamParameters
to SendByteStreamParameters
, etc. and the various method names correspondingly. That being said, I think it makes sense to incorporate the type of stream into the interface in general to avoid confusion in a dynamically typed language (what kind of stream is this? a stream of bananas?), so this is IMO a good idea to implement regardless of this proposal.
Using the body mixin for OutgoingMessage
/IncomingMessage
would be a more flexible API but might introduce more complexity, too. I also do not particularly like that it's a ReadableStream
for both roles (when reading and when writing) and I don't really know if that would be an ergonomic approach for sending (at least when it comes to terminology, it's awkward). I'm also concerned that it would make piping harder. All of these concerns should be discussed before going with the latter suggestion.
Thoughts? I realise these changes and additions are quite substantial... if you think there's an easier way to achieve the same, let's discuss it.
/cc @ricea