feat: Add streaming support (#125)

This adds:
- [x] Keyboard and mouse handling on the frontend
- [x] Video and audio streaming from the backend to the frontend
- [x] Input server that works with Websockets

Update - 17/11
- [ ] Master docker container to run this
- [ ] Steam runtime
- [ ] Entrypoint.sh

---------

Co-authored-by: Kristian Ollikainen <14197772+DatCaptainHorse@users.noreply.github.com>
Co-authored-by: Kristian Ollikainen <DatCaptainHorse@users.noreply.github.com>
This commit is contained in:
Wanjohi
2024-12-08 14:54:56 +03:00
committed by GitHub
parent 5eb21eeadb
commit 379db1c87b
137 changed files with 12737 additions and 5234 deletions

View File

@@ -0,0 +1,63 @@
import * as Hex from "../common/hex"
import { Connection } from "./connection"
import * as Message from "./message"
import { Stream } from "./stream"
export interface ClientConfig {
url: string
// If set, the server fingerprint will be fetched from this URL.
// This is required to use self-signed certificates with Chrome (May 2023)
fingerprint?: string
}
export class Client {
#fingerprint: Promise<WebTransportHash | undefined>
readonly config: ClientConfig
constructor(config: ClientConfig) {
this.config = config
this.#fingerprint = this.#fetchFingerprint(config.fingerprint).catch((e) => {
console.warn("failed to fetch fingerprint: ", e)
return undefined
})
}
async connect(): Promise<Connection> {
// Helper function to make creating a promise easier
const options: WebTransportOptions = {}
const fingerprint = await this.#fingerprint
if (fingerprint) options.serverCertificateHashes = [fingerprint]
const quic = new WebTransport(this.config.url, options)
await quic.ready
const client = new Message.SessionClient([Message.Version.FORK_02])
const stream = await Stream.open(quic, client)
const server = await Message.SessionServer.decode(stream.reader)
if (server.version !== Message.Version.FORK_02) {
throw new Error(`unsupported server version: ${server.version}`)
}
console.log(`established connection: version=${server.version}`)
return new Connection(quic, stream)
}
async #fetchFingerprint(url?: string): Promise<WebTransportHash | undefined> {
if (!url) return
// TODO remove this fingerprint when Chrome WebTransport accepts the system CA
const response = await fetch(url)
const bytes = Hex.decode(await response.text())
return {
algorithm: "sha-256",
value: bytes,
}
}
}