mailbox.ts 1.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. import { createSignal } from './signal.js'
  2. export type MessageSource = 'user' | 'teammate' | 'system' | 'tick' | 'task'
  3. export type Message = {
  4. id: string
  5. source: MessageSource
  6. content: string
  7. from?: string
  8. color?: string
  9. timestamp: string
  10. }
  11. type Waiter = {
  12. fn: (msg: Message) => boolean
  13. resolve: (msg: Message) => void
  14. }
  15. export class Mailbox {
  16. private queue: Message[] = []
  17. private waiters: Waiter[] = []
  18. private changed = createSignal()
  19. private _revision = 0
  20. get length(): number {
  21. return this.queue.length
  22. }
  23. get revision(): number {
  24. return this._revision
  25. }
  26. send(msg: Message): void {
  27. this._revision++
  28. const idx = this.waiters.findIndex(w => w.fn(msg))
  29. if (idx !== -1) {
  30. const waiter = this.waiters.splice(idx, 1)[0]
  31. if (waiter) {
  32. waiter.resolve(msg)
  33. this.notify()
  34. return
  35. }
  36. }
  37. this.queue.push(msg)
  38. this.notify()
  39. }
  40. poll(fn: (msg: Message) => boolean = () => true): Message | undefined {
  41. const idx = this.queue.findIndex(fn)
  42. if (idx === -1) return undefined
  43. return this.queue.splice(idx, 1)[0]
  44. }
  45. receive(fn: (msg: Message) => boolean = () => true): Promise<Message> {
  46. const idx = this.queue.findIndex(fn)
  47. if (idx !== -1) {
  48. const msg = this.queue.splice(idx, 1)[0]
  49. if (msg) {
  50. this.notify()
  51. return Promise.resolve(msg)
  52. }
  53. }
  54. return new Promise<Message>(resolve => {
  55. this.waiters.push({ fn, resolve })
  56. })
  57. }
  58. subscribe = this.changed.subscribe
  59. private notify(): void {
  60. this.changed.emit()
  61. }
  62. }