Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
78e8aad
I have no idea why this doesn't work.
ValorZard Nov 5, 2025
792b0d4
Move to axum webserver
ValorZard Nov 5, 2025
e5c5a82
Well, we have a connection at least.
ValorZard Nov 5, 2025
fe6fa77
Stopping here, will wait for review.
ValorZard Nov 5, 2025
da9c33d
Works, but it's a bit jank
ValorZard Nov 5, 2025
c0ded15
Remove unnecessary sleep
ValorZard Nov 5, 2025
83f9efd
Better error handling from SSE side
ValorZard Nov 5, 2025
4f8f23c
Merge pull request #14 from pion/go-sse
ValorZard Nov 5, 2025
510f7db
Add axum SSE example
ValorZard Nov 5, 2025
22c321a
Remove unneeded code
ValorZard Nov 5, 2025
09e02f3
Merge pull request #15 from pion/rust-sse
ValorZard Nov 5, 2025
0d891fe
Update README with SSE information
ValorZard Nov 5, 2025
81e4460
Merge pull request #16 from pion/rust-sse
ValorZard Nov 5, 2025
5fd3e0d
Add basic signaling server
ValorZard Nov 5, 2025
b7cb09f
Won't build due to linker errors
ValorZard Nov 5, 2025
6a0ad71
Switching to dimpl doesn't help
ValorZard Nov 5, 2025
f0670fb
We have an rtc connection going
ValorZard Nov 6, 2025
1fbd97d
ICE gets stuck in checking
ValorZard Nov 6, 2025
c2031b7
Remove unnecessary configure
ValorZard Nov 6, 2025
5e53219
Add nix flakes
JoeTurki Nov 6, 2025
7591f93
Update gitignore
JoeTurki Nov 6, 2025
735158d
Use openssl on non-windows
JoeTurki Nov 6, 2025
5bf6a76
Update gitignore
JoeTurki Nov 6, 2025
9ab8e1d
Add setup-certs for flakes
JoeTurki Nov 6, 2025
79be45c
Add a note about
JoeTurki Nov 6, 2025
cb8ab80
Make str0m work
JoeTurki Nov 6, 2025
3879a44
Fix windows dependency
ValorZard Nov 6, 2025
dee5f5a
Fix str0m on windows
JoeTurki Nov 6, 2025
67d9b09
Remove some hacks
JoeTurki Nov 6, 2025
96db20a
Refactor and fixes
JoeTurki Nov 6, 2025
0682fc7
Stream data for graph
ValorZard Nov 6, 2025
c176a39
Handle different types of data
JoeTurki Nov 6, 2025
bddbf1d
Fix write on windows
JoeTurki Nov 6, 2025
7bd46a8
Better I/O and basic back pressure
JoeTurki Nov 6, 2025
2e1f3ca
Missing cargo features
JoeTurki Nov 6, 2025
0dcc7c6
Remove unnecessary println
ValorZard Nov 6, 2025
47782c8
Merge pull request #17 from pion/add-str0m
ValorZard Nov 6, 2025
34c1b39
Add str0m to readme
ValorZard Nov 6, 2025
1d2d392
Merge pull request #18 from pion/update-readme-again
ValorZard Nov 6, 2025
3387e93
I have no idea why this doesn't work.
ValorZard Nov 5, 2025
2bf3d38
Move to axum webserver
ValorZard Nov 5, 2025
b79a55a
Well, we have a connection at least.
ValorZard Nov 5, 2025
c5c2f6c
Stopping here, will wait for review.
ValorZard Nov 5, 2025
170c565
Merge branch 'rust-webrtc' of https://github.com/pion/realtime-web-co…
ValorZard Nov 6, 2025
3a42220
Add str0m to rust-analyzer settings
ValorZard Nov 6, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
# Nix
result
result-*

# Rust
target/
**/*.rs.bk
*.pdb
debug/

.idea/
certs/
*.pem
Expand All @@ -20,3 +30,12 @@ target

# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb

bin/
vendor/
node_modules/

cover.out
*.wasm

*~
7 changes: 7 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"rust-analyzer.linkedProjects": [
"webrtc\\webrtc-rs-server\\Cargo.toml",
"webrtc\\str0m-server\\Cargo.toml",
"websocket\\tungstenite-server\\Cargo.toml"
]
}
86 changes: 75 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# realtime-web-comparison
Experimenting with WebSocket, WebRTC, and WebTransport by streaming 2500 coordinates from server to client to visualize.
Experimenting with Server Sent Events, WebSocket, WebRTC, and WebTransport by streaming 2500 coordinates from server to client to visualize.

# NOTE: This repository is currently in flux.
- The WebTransport server currently does not work, however WebSockets and the WebRTC datachannels do
# NOTE: This repository is currently in flux.
- The WebTransport server currently does not work
- We're doing our best to update all code to the latest versions of their dependencies.

**Additional notes:**
Expand All @@ -11,14 +11,37 @@ Experimenting with WebSocket, WebRTC, and WebTransport by streaming 2500 coordin

- No limits were specified on packet size or how protocols buffer packets.

The pseudo code of what each test is doing looks somewhat like this:

```go
for i := 10; i < 510; i += 10 {
for j := 10; j < 510; j += 10 {
message := fmt.Sprintf("%d,%d", j, i)
if err := conn.WriteMessage(websocket.TextMessage, []byte(message)); err != nil {
log.Fatal(err)
}
time.Sleep(1 * time.Millisecond)
}
}
```

## TODO
- [Add more options for each network connection type](https://github.com/pion/realtime-web-comparison/issues/6)
- Add more libraries to test.

## Dependencies
- Server Sent Events
- [tmaxmax/go-sse](https://github.com/tmaxmax/go-sse)
- [tokio-rs/axum](https://github.com/tokio-rs/axum)
- WebSockets
- [gorilla/websocket](https://github.com/gorilla/websocket)
- [snapview/tungstenite-rs](https://github.com/snapview/tungstenite-rs)
- WebRTC
- [pion/webrtc](https://github.com/pion/webrtc)
- [algesten/str0m](https://github.com/algesten/str0m)
- WebTransport
- [adriancable/webtransport-go](https://github.com/adriancable/webtransport-go)
- Client is written in pure HTML/CSS/JS.
- Client is written in pure HTML/CSS/JS.
- For CSS: [Bootstrap](https://getbootstrap.com/)
- The chart visualization is done using [Chart.js](https://www.chartjs.org/).

Expand All @@ -30,12 +53,16 @@ Experimenting with WebSocket, WebRTC, and WebTransport by streaming 2500 coordin
cd realtime-web-comparison
```

2. Create locally trusted certs using [mkcert](https://github.com/FiloSottile/mkcert)
```bash
mkdir certs && cd certs
mkcert -install
mkcert localhost
```
2. Create locally trusted certs using [mkcert](https://github.com/FiloSottile/mkcert)
```bash
mkdir certs && cd certs
mkcert -install
mkcert localhost
```
If using Nix flakes (see [Nix Setup Flakes](#nix-setup) section above):
```bash
nix run .#setup-certs
```

3. Run a server (use similar commands for `webtransport` and `webrtc`)
```bash
Expand All @@ -46,10 +73,47 @@ Experimenting with WebSocket, WebRTC, and WebTransport by streaming 2500 coordin
```bash
sudo tc qdisc add dev lo root netem loss 15%
```

5. Run client
```bash
./run.sh client
chromium --origin-to-force-quic-on=localhost:8001 http://localhost:3000
```

## Nix Setup

This repository includes a Nix flake for reproducible development environments. The flake provides all necessary dependencies including Rust, Go, OpenSSL, and mkcert.

### Development Shell

Enter the development shell to get all tools in your PATH:

```bash
nix develop
```

This provides:
- Rust toolchain (rustc, cargo, rustfmt, clippy, rust-analyzer)
- Go toolchain
- OpenSSL with proper environment variables configured
- mkcert for certificate generation
- NSS tools (for Firefox support on Linux)

### Setting Up Certificates

Use the Nix task to automatically set up locally trusted certificates:

```bash
nix run .#setup-certs
```

The `setup-certs` task will:
- Create the `certs/` directory if it doesn't exist
- Install the local CA certificate in your system trust store
- Generate a certificate for `localhost`

### Available Tasks

- `nix run .#setup-certs` - Set up development certificates using mkcert

Note: you might need to run `nix develop -c mkcert -install` and restart your browsers.
2 changes: 2 additions & 0 deletions client/static/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
<button id="websocket" type="button" class="btn btn-outline-dark">WebSocket</button>
<button id="webrtc" type="button" class="btn btn-outline-dark">WebRTC</button>
<button id="webtransport" type="button" class="btn btn-outline-dark">WebTransport</button>
<button id="sse" type="button" class="btn btn-outline-dark">Server Sent Events</button>
</div>
</header>

Expand All @@ -41,4 +42,5 @@ <h5 class="card-title">Stats</h5>
<script src='js/websocket.js' type="module"></script>
<script src='js/webtransport.js' type="module"></script>
<script src='js/webrtc.js' type="module"></script>
<script src='js/sse.js' type="module"></script>
</html>
6 changes: 6 additions & 0 deletions client/static/js/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ export let chart = new Chart(chartContext, {
showLine: true,
borderDash: [2, 5],
},
{
data: [],
label: "Server Sent Events",
borderColor: "#000000ff",
showLine: true,
}
]
},
options: {
Expand Down
50 changes: 50 additions & 0 deletions client/static/js/sse.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import {chart, initCanvas, visualizePacket} from "./common.js";

const sseBtn = document.getElementById("sse");
const serverUrl = "http://localhost:7999";

sseBtn.onclick = (_) => {
initCanvas()
console.info(`Connecting to Server Sent Events server at ${serverUrl} ...`);

let t0 = new Date();
let messageCount = 0;
const eventSource = new EventSource(serverUrl);

eventSource.onopen = (_) => {
console.info(`Connection established in ${new Date() - t0} ms.`);
sseBtn.disabled = true
t0 = new Date();
chart.data.datasets[3].data.push({x: 0, y: 0});
}

eventSource.onmessage = (e) => {
messageCount += 1;
visualizePacket(e.data);
if (new Date() - t0 - chart.data.datasets[3].data.at(-1).x > 200) {
chart.data.datasets[3].data.push({x: new Date() - t0, y: messageCount});
chart.update();
}

// Check if we've received all messages (2500 total: 50x50)
if (messageCount >= 2500) {
eventSource.close();
console.info(`${messageCount} message(s) were received within ${new Date() - t0} ms.`)
console.info('All messages received. Disconnected from Server Sent Events server.');
sseBtn.disabled = false;
}
}

eventSource.onerror = (err) => {
console.error('SSE connection error:', err);
eventSource.close();
sseBtn.disabled = false;

if (messageCount > 0) {
// Connection dropped mid-stream
chart.data.datasets[3].data.push({x: new Date() - t0, y: messageCount});
chart.update();
console.info(`Connection interrupted. ${messageCount} message(s) were received within ${new Date() - t0} ms.`)
}
}
}
22 changes: 18 additions & 4 deletions client/static/js/webrtc.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ webRTCBtn.onclick = (_) => {
conn.onconnectionstatechange = () => {
console.info(`WebRTC Connection State: ${conn.connectionState}`);
};

conn.oniceconnectionstatechange = () => {
console.info(`ICE Connection State: ${conn.iceConnectionState}`);
};

conn.onicegatheringstatechange = () => {
console.info(`ICE Gathering State: ${conn.iceGatheringState}`);
};
Expand Down Expand Up @@ -61,14 +61,28 @@ webRTCBtn.onclick = (_) => {
console.info(`WebRTC DataChannel established in ${new Date() - t0} ms.`);
};

dataChannel.onmessage = (e) => {
dataChannel.onmessage = async (e) => {
if (messageCount === 0) {
webRTCBtn.disabled = true;
t0 = new Date();
chart.data.datasets[2].data.push({x: 0, y: 0});
}
messageCount += 1;
visualizePacket(decoder.decode(e.data));
let decoded;
if (typeof e.data === 'string') {
decoded = e.data;
} else if (e.data instanceof Blob) {
const buffer = await e.data.arrayBuffer();
decoded = decoder.decode(buffer);
} else if (e.data instanceof ArrayBuffer) {
decoded = decoder.decode(e.data);
} else if (e.data instanceof Uint8Array || e.data instanceof DataView) {
decoded = decoder.decode(e.data);
} else {
// fallback: try to convert to string
decoded = String(e.data);
}
visualizePacket(decoded);
if (new Date() - t0 - chart.data.datasets[2].data.at(-1).x > 200) {
chart.data.datasets[2].data.push({x: new Date() - t0, y: messageCount});
chart.update();
Expand Down
61 changes: 61 additions & 0 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading