74 lines
1.6 KiB
TypeScript
74 lines
1.6 KiB
TypeScript
import { createSignal } from './signal.js'
|
|
|
|
export type MessageSource = 'user' | 'teammate' | 'system' | 'tick' | 'task'
|
|
|
|
export type Message = {
|
|
id: string
|
|
source: MessageSource
|
|
content: string
|
|
from?: string
|
|
color?: string
|
|
timestamp: string
|
|
}
|
|
|
|
type Waiter = {
|
|
fn: (msg: Message) => boolean
|
|
resolve: (msg: Message) => void
|
|
}
|
|
|
|
export class Mailbox {
|
|
private queue: Message[] = []
|
|
private waiters: Waiter[] = []
|
|
private changed = createSignal()
|
|
private _revision = 0
|
|
|
|
get length(): number {
|
|
return this.queue.length
|
|
}
|
|
|
|
get revision(): number {
|
|
return this._revision
|
|
}
|
|
|
|
send(msg: Message): void {
|
|
this._revision++
|
|
const idx = this.waiters.findIndex(w => w.fn(msg))
|
|
if (idx !== -1) {
|
|
const waiter = this.waiters.splice(idx, 1)[0]
|
|
if (waiter) {
|
|
waiter.resolve(msg)
|
|
this.notify()
|
|
return
|
|
}
|
|
}
|
|
this.queue.push(msg)
|
|
this.notify()
|
|
}
|
|
|
|
poll(fn: (msg: Message) => boolean = () => true): Message | undefined {
|
|
const idx = this.queue.findIndex(fn)
|
|
if (idx === -1) return undefined
|
|
return this.queue.splice(idx, 1)[0]
|
|
}
|
|
|
|
receive(fn: (msg: Message) => boolean = () => true): Promise<Message> {
|
|
const idx = this.queue.findIndex(fn)
|
|
if (idx !== -1) {
|
|
const msg = this.queue.splice(idx, 1)[0]
|
|
if (msg) {
|
|
this.notify()
|
|
return Promise.resolve(msg)
|
|
}
|
|
}
|
|
return new Promise<Message>(resolve => {
|
|
this.waiters.push({ fn, resolve })
|
|
})
|
|
}
|
|
|
|
subscribe = this.changed.subscribe
|
|
|
|
private notify(): void {
|
|
this.changed.emit()
|
|
}
|
|
}
|