Socket.ts 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. // eslint-disable-next-line @typescript-eslint/ban-ts-comment
  2. // @ts-ignore no types
  3. import ee from 'namespace-emitter'
  4. type Opts = {
  5. autoOpen?: boolean
  6. target: string
  7. }
  8. export default class UppySocket {
  9. #queued: Array<{ action: string; payload: unknown }> = []
  10. #emitter = ee()
  11. #isOpen = false
  12. #socket: WebSocket | null
  13. opts: Opts
  14. constructor(opts: Opts) {
  15. this.opts = opts
  16. if (!opts || opts.autoOpen !== false) {
  17. this.open()
  18. }
  19. }
  20. get isOpen(): boolean {
  21. return this.#isOpen
  22. }
  23. private [Symbol.for('uppy test: getSocket')](): WebSocket | null {
  24. return this.#socket
  25. }
  26. private [Symbol.for('uppy test: getQueued')](): Array<{
  27. action: string
  28. payload: unknown
  29. }> {
  30. return this.#queued
  31. }
  32. open(): void {
  33. if (this.#socket != null) return
  34. this.#socket = new WebSocket(this.opts.target)
  35. this.#socket.onopen = () => {
  36. this.#isOpen = true
  37. while (this.#queued.length > 0 && this.#isOpen) {
  38. const first = this.#queued.shift()
  39. // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
  40. this.send(first!.action, first!.payload)
  41. }
  42. }
  43. this.#socket.onclose = () => {
  44. this.#isOpen = false
  45. this.#socket = null
  46. }
  47. this.#socket.onmessage = this.#handleMessage
  48. }
  49. close(): void {
  50. this.#socket?.close()
  51. }
  52. send(action: string, payload: unknown): void {
  53. // attach uuid
  54. if (!this.#isOpen) {
  55. this.#queued.push({ action, payload })
  56. return
  57. }
  58. this.#socket!.send(
  59. JSON.stringify({
  60. action,
  61. payload,
  62. }),
  63. )
  64. }
  65. on(action: string, handler: () => void): void {
  66. this.#emitter.on(action, handler)
  67. }
  68. emit(action: string, payload: unknown): void {
  69. this.#emitter.emit(action, payload)
  70. }
  71. once(action: string, handler: () => void): void {
  72. this.#emitter.once(action, handler)
  73. }
  74. #handleMessage = (e: MessageEvent<any>) => {
  75. try {
  76. const message = JSON.parse(e.data)
  77. this.emit(message.action, message.payload)
  78. } catch (err) {
  79. // TODO: use a more robust error handler.
  80. console.log(err) // eslint-disable-line no-console
  81. }
  82. }
  83. }