Files
netris-nestri/packages/moq/common/async.ts
Wanjohi 379db1c87b 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>
2024-12-08 14:54:56 +03:00

129 lines
2.4 KiB
TypeScript

export class Deferred<T> {
promise: Promise<T>
resolve!: (value: T | PromiseLike<T>) => void
reject!: (reason: unknown) => void
pending = true
constructor() {
this.promise = new Promise((resolve, reject) => {
this.resolve = (value) => {
this.pending = false
resolve(value)
}
this.reject = (reason) => {
this.pending = false
reject(reason)
}
})
}
}
export type WatchNext<T> = [T, Promise<WatchNext<T>> | undefined]
export class Watch<T> {
#current: WatchNext<T>
#next = new Deferred<WatchNext<T>>()
constructor(init: T) {
this.#next = new Deferred<WatchNext<T>>()
this.#current = [init, this.#next.promise]
}
value(): WatchNext<T> {
return this.#current
}
update(v: T | ((v: T) => T)) {
if (!this.#next.pending) {
throw new Error("closed")
}
// If we're given a function, call it with the current value
let value: T
if (v instanceof Function) {
value = v(this.#current[0])
} else {
value = v
}
const next = new Deferred<WatchNext<T>>()
this.#current = [value, next.promise]
this.#next.resolve(this.#current)
this.#next = next
}
close() {
this.#current[1] = undefined
this.#next.resolve(this.#current)
}
closed() {
return !this.#next.pending
}
}
// Wakes up a multiple consumers.
export class Notify {
#next = new Deferred<void>()
async wait() {
return this.#next.promise
}
wake() {
if (!this.#next.pending) {
throw new Error("closed")
}
this.#next.resolve()
this.#next = new Deferred<void>()
}
close() {
this.#next.resolve()
}
}
// Allows queuing N values, like a Channel.
export class Queue<T> {
#stream: TransformStream<T, T>
#closed = false
constructor(capacity = 1) {
const queue = new CountQueuingStrategy({ highWaterMark: capacity })
this.#stream = new TransformStream({}, undefined, queue)
}
async push(v: T) {
if (this.#closed) throw new Error("closed")
const w = this.#stream.writable.getWriter()
await w.write(v)
w.releaseLock()
}
async next(): Promise<T | undefined> {
const r = this.#stream.readable.getReader()
const { value, done } = await r.read()
r.releaseLock()
if (done) return
return value
}
async abort(err: Error) {
if (this.#closed) return
await this.#stream.writable.abort(err)
this.#closed = true
}
async close() {
if (this.#closed) return
await this.#stream.writable.close()
this.#closed = true
}
closed() {
return this.#closed
}
}