- Intro
- What Is HTTP/3
- Dissecting The WebTransport Class
- WebTransport Use Cases
- Why I Created ShakePort
- The Code
People Are SLEEPING on WebTransport!
Of all my favorite HTML APIs the WebTransport API is definitely TOP 3. MDN explains the WebTransport API as such:
The
https://developer.mozilla.org/en-US/docs/Web/API/WebTransportWebTransport
interface of the WebTransport API provides functionality to enable a user agent to connect to an HTTP/3 server, initiate reliable and unreliable transport in either or both directions, and close the connection once it is no longer needed.
It allows a web page to connect to a bidirectional HTTP/3 server to send and receive UDP datagrams either reliably or unreliably. Seriously why is no one talking about this?! In this article/tutorial, I will go through the process of creating an NPM package called ShakePort
What Is HTTP/3
HTTP/3 is the third major version of the Hypertext Transfer Protocol used to exchange information on the World Wide Web, complementing the widely-deployed HTTP/1.1 and HTTP/2. Unlike previous versions which relied on the well-established TCP (published in 1974),[1] HTTP/3 uses QUIC, a multiplexed transport protocol built on UDP.[2] On 6 June 2022, IETF published HTTP/3 as a Proposed Standard in RFC9114.[3]
https://en.wikipedia.org/wiki/HTTP/3
HTTP/3 is 3x faster than HTTP/1.1 and has much less latency than its predecessors. Built using QUIC for data transfer using UDP instead of TCP. What this means for real-time sensitive applications is faster data faster execution.
Listen To Some Hacker Music While You Code
Dissecting The WebTransport Class
Constructor
The constructor for the WebTransport takes in a url and an options parameter. The URL points to an instance of a HTTP/3 server to connect to. The options parameter is an optional variable that passes in a JSON object
url
A string representing the URL of the HTTP/3 server to connect to. The scheme needs to be HTTPS, and the port number needs to be explicitly specified.options
Optional
An object containing the following properties:serverCertificateHashes
Optional
An array of WebTransportHash
objects. If specified, it allows the website to connect to a server by authenticating the certificate against the expected certificate hash instead of using the Web public key infrastructure (PKI). This feature allows Web developers to connect to WebTransport servers that would normally find obtaining a publicly trusted certificate challenging, such as hosts that are not publicly routable, or ephemeral hosts like virtual machines.
WebTransportHash
objects contain two properties:algorithm
A string representing the algorithm to use to verify the hash. Any hash using an unknown algorithm will be ignored.value
A BufferSource
representing the hash value.
We instantiate a new instance of WebTransport with the following command
new WebTransport(url, options)
Instance Properties
The closed
read-only property of the WebTransport
interface returns a promise that resolves when the transport is closed.
The datagrams
read-only property of the WebTransport
interface returns a WebTransportDatagramDuplexStream
instance that can be used to send and receive datagrams — unreliable data transmission.
“Unreliable” means that transmission of data is not guaranteed, nor is arrival in a specific order. This is fine in some situations and provides very fast delivery. For example, you might want to transmit regular game state updates where each message supersedes the last one that arrives, and order is not important.
The incomingBidirectionalStreams
read-only property of the WebTransport
interface represents one or more bidirectional streams opened by the server. Returns a ReadableStream
of WebTransportBidirectionalStream
objects. Each one can be used to reliably read data from the server and write data back to it.
The incomingUnidirectionalStreams
read-only property of the WebTransport
interface represents one or more unidirectional streams opened by the server. Returns a ReadableStream
of WebTransportReceiveStream
objects. Each one can be used to reliably read data from the server.
The ready
read-only property of the WebTransport
interface returns a promise that resolves when the transport is ready to use.
Instance Methods
The close()
method of the WebTransport
interface closes an ongoing WebTransport session.
The createBidirectionalStream()
method of the WebTransport
interface opens a bidirectional stream; it returns a WebTransportBidirectionalStream
object containing readable
and writable
properties, which can be used to reliably read from and write to the server.
The createUnidirectionalStream()
method of the WebTransport
interface opens a unidirectional stream; it returns a WritableStream
object that can be used to reliably write data to the server.
Use Cases For WebTransport
Web Gaming
WebTransport allows not only for better performance web games in multiplayer, but it also allows for CROSS-SYSTEM PLAY! Since WebTransport is an HTTP/3 web standard you can implement it on the web, PlayStation, Xbox, and whatever else may come in the future! You may be wondering why use WebTransport instead of WebRTC. For 1 v 1 multiplayer games WebRTC will do just fine, but what if you want to build a Battle Royale style battle game that’s 50 v 50? If you are using WebRTC you will run into latency issues because WebRTC is peer-to-peer whereas WebTransport is client-server. Using UDP packets so order does not matter which is what you want for gaming.
IOT
With WebTransport communicating with IOT devices via the web just got a whole lot easier. You can manage a fleet of hardware devices, get analytical data and issue commands in real-time. I am currently using a WebTransport server on my Raspberry Pi 4 and a Vue frontend to remotely control my Pi!
Machine Learning
Machine learning requires large datasets. By utilizing WebTransport you can send user data to your server in real-time to get better insights on your machine learning models. Take for example you are building a recommendation engine. As the user browses the site, you are sending data in real time based on what they are looking at, etc. The faster you can collect and analyze data, the more profitable your company can become.
Pub/Sub
Using the WebTransport API you can implement a pub/sub system. The simplest use case would be a notification engine (think game HUD updates in multiplayer). You can also do things like implement real-time tickers instead of relying on long-polling techniques.
Why I Created ShakePort
I created ShakePort as a basis for my real-time apps and more importantly, I’m building a game and need multiplayer networking. I decided at the beginning of the year I would post on average 1 open source package a month. So far I’m at 4! My philosophy is if you find yourself doing certain code over and over, just package that sh!t up and release it to the world. Chances are there are other developers who you are helping OR you could find devs to help make your package even better! The ShakePort suite is made up of a client (ShakePort Client) and a server (ShakePort Server) this tutorial will focus on the ShakePort Client, I will post the ShakePort Server tutorial later in the year once I finish.
The Code
This package is actually very simple, it only consists of two files:
- A WebWorker file
- The ShakePortClient class
Almost all of the heavy work is offloaded to the WebWorker to optimize speed and performance and utilizes window.postMessage()
to send data to the main application. This way the developer has custom control on how to deal with the datagrams.
Scaffolding
Create a new directory and run the npm init command to create a new NPM packagemkdir shakeport-client
cd shakeport-client && npm init
The WebWorker
Create a worker.js file in the root of the project and input the following:
let transport, stream = null
onmessage = (e) => {
try {
switch(e.data.event) {
case 'start':
transport = initTransport(e.data.url, e.data.options)
postMessage({event:'start', transport:transport})
break;
case 'setup-bidirectional':
stream = setUpBidirectional()
readData(stream.readable)
break;
case 'write-bidirectional':
writeData(stream.writable, e.data.data)
break;
case 'data':
break;
case 'stop':
closeTransport(e.transport)
break;
}
} catch {
postMessage({event: 'error'});
}
}
async function initTransport(url, options = {}) {
// Initialize transport connection
const transport = new WebTransport(url, options);
// The connection can be used once ready fulfills
await transport.ready;
return transport
}
async function readData(readable) {
const reader = readable.getReader();
while (true) {
const {value, done} = await reader.read();
if (done) {
break;
}
// value is a Uint8Array.
postMessage({event: 'data-read', data:value});
}
}
async function writeData(writable, data) {
const writer = writable.getWriter();
writer.write(data)
postMessage({event: 'data-written', data: data})
}
async function setUpBidirectional() {
const stream = await transport.createBidirectionalStream();
// stream is a WebTransportBidirectionalStream
// stream.readable is a ReadableStream
// stream.writable is a WritableStream
return stream
}
async function setUpUnidirectional() {
const stream = await transport.createUnidirectionalStream();
// stream is a WebTransportBidirectionalStream
// stream.readable is a ReadableStream
// stream.writable is a WritableStream
return stream
}
async function closeTransport(transport) {
// Respond to connection closing
try {
await transport.closed;
console.log(`The HTTP/3 connection to ${url} closed gracefully.`);
} catch(error) {
console.error(`The HTTP/3 connection to ${url} closed due to ${error}.`);
}
}
The ShakePortClient Class
Create a class file called ShakePortClient.js in the root directory and fill it in:
export default class ShakePortClient {
transport = null
constructor() {
const worker = require('./worker.js')
console.log(worker)
this.worker = new Worker(worker)
}
startClient(data = {url, options: {}}) {
this.worker.postMessage({event:'start', ...data})
this.worker.onmessage = (event) => {
switch(event.data.event) {
case 'start':
console.log('Started')
this.transport = event.data.transport
break;
case 'stop':
this.transport = null
break;
case 'error':
console.log(event.data.error)
break;
default:
window.postMessage(event.data)
break;
}
}
}
stopClient () {
this.worker.postMessage({event:'stop'})
}
setUpBidirectional () {
this.worker.postMessage({event:'setup-bidirectional'})
}
setUpUnidirectional () {
this.worker.postMessage({event:'setup-unidirectional'})
}
writeBidirectional (data) {
this.worker.postMessage({event:'write-bidirectional', data: data})
}
writeData (data) {
this.worker.postMessage({event:'write-data', data: data})
}
writeUndirectional (data) {
this.worker.postMessage({event:'write-unidirectional', data: data})
}
}
Using The Package
npm install @mastashake08/shakeport-client
Then import and use
Import In Your Project
import ShakePortClient from '@mastashake08/shakeport-client'
const spc = new ShakePortClient();
spc.startClient({
url:'<webtransport_server_url>'
})
Responding To Messages
window.addEventListener("message", (event) => {
// Do we trust the sender of this message? (might be
// different from what we originally opened, for example).
if (event.origin !== "http://example.com")
return;
// event.source is popup
// event.data is "hi there yourself! the secret response is: rheeeeet!"
}, false);
Follow Me On Social Media
Follow Me On Youtube!
Get Your Next Domain Cheap & Support The Channel
I use Namecheap for all of my domains! Whenever I need a cheap solution for a proof-of-concept project I grab a domain name for as little as $1! When you sign up and buy your first domain with Namecheap I get a commission, it’s a great way to get a quality service and support this platform!
Get Your Next Domain Cheap
CLICK HERE
Become A Sponsor
Open-source work is free to use but it is not free to develop. If you enjoy my content and would like to see more please consider becoming a sponsor on Github or Patreon! Not only do you support me but you are funding tech programs for at risk youth in Louisville, Kentucky.
Join The Newsletter
By joining the newsletter, you get first access to all of my blogs, events, and other brand-related content delivered directly to your inbox. It’s 100% free and you can opt out at any time!
Check The Shop
You can also consider visiting the official #CodeLife shop! I have my own clothing/accessory line for techies as well as courses designed by me covering a range of software engineering topics.
-
Product on saleGPT Genie: A Solo Developer’s Guide to Mastering ChatGPT$1.99
-
These Fingers Unisex t-shirt$23.55 – $31.55
-
#CodeLife AirPods case$15.00
-
Embroidered #CodeLife Champion Backpack$44.50
-
#CodeLife Laptop Sleeve$25.00 – $28.00
-
#CodeLife Unisex T-Shirt$20.00 – $22.00
-
#CodeLife Unisex Joggers$31.50 – $33.50
-
Cuffed #CodeLife Beanie$20.00
-
Unisex #CodeLife Hoodie$36.50 – $38.50
[…] submitted by /u/One-Ad1988 [link] […]
[…] submitted by /u/One-Ad1988 [link] […]