permalinkuseWebWorker

Here's a Hook you can use with yoga-web-proletarian to create a Web Worker and send messages to it.

src/Hooks/UseWebworker.purs
-- use client
module Hooks.UseWebWorker where

import Prelude

import Data.Newtype (class Newtype)
import React.Basic.Hooks as React
import Yoga.WebBoss (onMessageFromWorker, postMessageToWorker, terminate)
import Yoga.WebProletarian.Types (Worker)
import Effect.AVar as AVar
import Effect.AVar (AVar)
import Effect.Aff.AVar as AffVar
import Effect.Aff (launchAff_)
import Effect.Class (liftEffect)
import Control.Promise (toAffE, Promise)
import React.Basic.Hooks (UseEffect, UseRef)
import Data.Maybe (Maybe, Maybe(..))
import Effect (Effect)
import React.Basic.Hooks.Internal (Hook, coerceHook)
import Data.Foldable (traverse_)

newtype UseWebWorker from to hooks = UseWebWorker
  ( UseEffect Unit
      (UseRef (Maybe ({ worker  Worker from to, mutex  AVar Unit })) hooks)
  )

derive instance Newtype (UseWebWorker from to hooks) _

useWebWorker
    toWorker fromWorker
  . Effect (Promise (Worker toWorker fromWorker))
  → (fromWorker → Effect Unit)
Hook (UseWebWorker toWorker fromWorker) (toWorker → Effect Unit)
useWebWorker newWorker handler = coerceHook React.do
  workerRef ← React.useRef Nothing
  React.useEffectOnce do
    launchAff_ do
      worker ← newWorker # toAffE
      mutex ← AffVar.new unit
      liftEffect $ worker # onMessageFromWorker \msg → launchAff_ do
        handler msg # liftEffect
        AffVar.put unit mutex
      React.writeRef workerRef (Just { worker, mutex }) # liftEffect
    pure do
      React.readRef workerRef >>=
        (traverse_ \{ worker, mutex } → terminate worker)
  pure \msg → do
    React.readRef workerRef
      >>= traverse_
        \{ worker, mutex } → launchAff_ do
          AffVar.take mutex
          postMessageToWorker msg worker # liftEffect