OverviewFilesCommitsIssuesDocsReleasesPeers

holepunchto-deps / @holepunchto / keet-media / client.js

90 lines · javascript ref:
import ReadyResource from 'ready-resource'
import { isImageSupported, isMediaSupported, isVideoSupported } from 'bare-media/types'

import HRPC from './shared/spec/hrpc/index.js'

const RPC_METHODS = [
  'createChatImagePreview',
  'createChatVideoPreview',
  'createChatLinkPreview',
  'createProfileAvatar',
  'createRoomAvatar',
  'decodeImage'
]

export class WorkerClient extends ReadyResource {
  spawn = null
  worker = null
  rpc = null
  opts = null

  constructor(opts) {
    super()

    for (const method of RPC_METHODS) {
      this.#createRpcMethod(method)
    }

    this.initialize(opts)
  }

  #createRpcMethod(method) {
    this[method] = async (...args) => {
      await this.ready()
      return this.rpc[method](...args)
    }
  }

  initialize({
    spawn,
    filename = 'node_modules/@holepunchto/keet-media/worker/index.js',
    requireSource,
    args
  } = {}) {
    this.spawn = spawn
    this.opts = { filename, requireSource, args }
  }

  async _open() {
    await this.#run()
  }

  async _close() {
    this.worker?.IPC.end()
  }

  #reset() {
    this.opening = null
    this.closing = null

    this.opened = false
    this.closed = false

    this.worker = null
    this.rpc = null
  }

  async #run() {
    const { filename, requireSource, args } = this.opts
    const source = requireSource?.()
    this.worker = await this.spawn(filename, source, args)

    const ipc = this.worker.IPC

    ipc.on('end', () => ipc.end())
    ipc.on('close', () => {
      this.#reset()
      this.onClose?.()
      console.error('[keet-media] Worker has exited. IPC channel closed unexpectedly.')
    })

    this.rpc = new HRPC(ipc)
  }

  isImageSupported = isImageSupported

  isVideoSupported = isVideoSupported

  isMediaSupported = isMediaSupported
}