Skip to content

Commit

Permalink
Update explainer.md
Browse files Browse the repository at this point in the history
Reflect the interface changes #134 and #135.
  • Loading branch information
yutakahirano committed Oct 15, 2020
1 parent cf5e015 commit 823599f
Showing 1 changed file with 46 additions and 36 deletions.
82 changes: 46 additions & 36 deletions explainer.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,22 +58,22 @@ encrypted and congestion-controlled communication.

## Proposed solutions

1. A set of generic transport mixins that can be provided by any transport,
1. A generic transport interface that can be provided by any transport,
but match closely with QUIC's capabilities.

2. A specific transport based on QUIC that implements all of the transport mixins.
2. The transport interface can talk [a QUIC based protocol](https://tools.ietf.org/html/draft-vvv-webtransport-quic).

3. A specific transport based on HTTP/3 that allows a subset of the transport
mixins able to be pooled with HTTP traffic (sharing a congestion control context).
3. The transport interface can talk [a HTTP/3 based protocol](https://tools.ietf.org/html/draft-vvv-webtransport-http3)
that allows web developers to reuse HTTP/3 connections (sharing a congestion control context).

## Example of sending unreliable game state to server using QUIC datagrams

```javascript
// The app provides a way to get a serialized state to send to the server
function getSerializedGameState() { ... }

const transport = new QuicTransport('example.com', 10001);
const datagramWriter = transport.sendDatagrams().getWriter();
const transport = new WebTransport('quic-transport://example.com:10001/path');
const datagramWriter = transport.writableDatagrams.getWriter();
setInterval(() => {
const message = getSerializedGameState();
datagramWriter.write(message);
Expand All @@ -86,10 +86,10 @@ setInterval(() => {
// The app provides a way to get a serialized state to send to the server.
function getSerializedGameState() { ... }

const transport = new QuicTransport('example.com', 10001);
const transport = new WebTransport('quic-transport://example.com:10001/path');
setInterval(async () => {
const message = getSerializedGameState();
const stream = await transport.createSendStream();
const stream = await transport.createUnidirectionaltream();
const writer = stream.writable.getWriter();
writer.write(message);
writer.close();
Expand All @@ -102,24 +102,25 @@ setInterval(async () => {
// The app provides a way to get a serialized media request to send to the server
function getSerializedMediaRequest() { ... }

const transport = new QuicTransport('example.com', 10001);
const transport = new WebTransport('quic-transport://example.com:10001/path');

const mediaSource = new MediaSource();
await new Promise(resolve => mediaSource.addEventListener('sourceopen', resolve, {once: true}));
const sourceBuffer = mediaSource.addSourceBuffer('video/webm; codecs="opus, vp09.00.10.08"');

// App-specific request
const mediaRequest = getSerializedMediaRequest();
const requestStream = await transport.createSendStream();
const requestStream = await transport.createUnidirectionaltream();
const requestWriter = requestStream.writable.getWriter();
requestWriter.write(mediaRequest);
requestWriter.close();

// Receive the responses.
for await (const responseStream of transport.receiveStreams()) {
const response = await responseStream.arrayBuffer();
sourceBuffer.appendBuffer(response);
await new Promise(resolve => sourceBuffer.addEventListener('update', () => resolve(), {once: true}));
for await (const receiveStream of transport.incomingUnidirectionalStreams) {
for await (const buffer of receiveStream.readable){
sourceBuffer.appendBuffer(buffer);
}
await new Promise(resolve => sourceBuffer.addEventListener('update', resolve, {once: true}));
}
```

Expand All @@ -131,9 +132,13 @@ function deserializeNotification(serializedNotification) { ... }
// The app also provides a way to serialize a "clicked" message to send to the server.
function serializeClickedMessage(notification) { ... }

const transport = new QuicTransport('example.com', 10001);
for await (const stream of transport.receiveBidirectionalStreams()) {
const notification = new Notification(deserializeNofitication(await stream.arrayBuffer()));
const transport = new WebTransport('quic-transport://example.com:10001/path');
for await (const stream of transport.incomingBidirectionalStreams) {
const buffers = []
for await (const buffer of stream.readable) {
buffers.push(buffer)
}
const notification = new Notification(deserializeNofitication(buffers));
notification.addEventListener('onclick', () => {
const clickMessage = encodeClickMessage(notification);
const writer = stream.writable.getWriter();
Expand All @@ -147,13 +152,13 @@ for await (const stream of transport.receiveBidirectionalStreams()) {

```javascript
const mediaSource = new MediaSource();
await new Promise(resolve => mediaSource.addEventListener('sourceopen', () => resolve(), {once: true}));
await new Promise(resolve => mediaSource.addEventListener('sourceopen', resolve, {once: true}));
const sourceBuffer = mediaSource.addSourceBuffer('video/webm; codecs="opus, vp09.00.10.08"');
const transport = new Http3Transport("/video");
await fetch('http://example.com/babyshark');
for await (const datagram of transport.receiveDatagrams()) {
const transport = new WebTransport('/video');
await fetch('https://example.com/babyshark');
for await (const datagram of transport.readableDatagrams) {
sourceBuffer.appendBuffer(datagram);
await new Promise(resolve => sourceBuffer.addEventListener('update', () => resolve(), {once: true}));
await new Promise(resolve => sourceBuffer.addEventListener('update', resolve, {once: true}));
}
```

Expand All @@ -163,16 +168,19 @@ for await (const datagram of transport.receiveDatagrams()) {
const mediaSource = new MediaSource();
await new Promise(resolve => mediaSource.addEventListener('sourceopen', () => resolve(), {once: true}));
const sourceBuffer = mediaSource.addSourceBuffer('video/webm; codecs="opus, vp09.00.10.08"');
const transport = new Http3Transport("https://example.com/video");
for await (const stream of transport.receiveStreams()) {
sourceBuffer.appendBuffer(await stream.arrayBuffer());
await new Promise(resolve => sourceBuffer.addEventListener('update', () => resolve(), {once: true}));
const transport = new WebTransport('https://example.com/video');
for await (const receiveStream of transport.incomingUnidirectionalStreams) {
for await (const buffer of receiveStream.readable){
sourceBuffer.appendBuffer(buffer);
}
await new Promise(resolve => sourceBuffer.addEventListener('update', resolve, {once: true}));
}
```

## Detailed design discussion

Any WebTransport can provide any of the following capabilities (mixins):
WebTransport supports multiple protocols, each of which provide some of the
following capabilities.

- Unidirectional streams are indefintely long streams of bytes in one direction
with back pressure applied
Expand All @@ -189,15 +197,17 @@ Any WebTransport can provide any of the following capabilities (mixins):
sending messages with less API complexity
and less network overhead than streams.

A QuicTransport is a WebTransport that maps directly to QUIC streams and
datagrams, which makes it easy to connect to servers that speak QUIC with
minimum overhead. It supports all of these capabilities.

An Http3Transport is a WebTransport that provides QUIC streams and datagrams
with slightly more overhead vs. a QuicTransport. It has the advantage that HTTP
and non-HTTP traffic can share the same network port and congestion control
context, and it may be pooled with other transports such that the transport may
be connected more quickly (by reusing an existing HTTP/3 connection).
[QuicTransport](https://tools.ietf.org/html/draft-vvv-webtransport-quic)
is a WebTransport that maps directly to QUIC streams and datagrams, which makes
it easy to connect to servers that speak QUIC with minimum overhead.
It supports all of these capabilities.

[Http3Transport](https://tools.ietf.org/html/draft-vvv-webtransport-http3) is a
WebTransport that provides QUIC streams and datagrams with slightly more overhead
vs. a QuicTransport. It has the advantage that HTTP and non-HTTP traffic can share
the same network port and congestion control context, and it may be pooled with other
transports such that the transport may be connected more quickly (by reusing an
existing HTTP/3 connection).

## Alternative designs considered

Expand Down

0 comments on commit 823599f

Please sign in to comment.