packages feed

sandwich-webdriver-0.3.0.0: src/Test/Sandwich/WebDriver/Internal/OnDemand.hs

module Test.Sandwich.WebDriver.Internal.OnDemand where

import Control.Monad.IO.Unlift
import Control.Monad.Logger
import Data.String.Interpolate
import Data.Text as T
import Test.Sandwich
import Test.Sandwich.WebDriver.Internal.Types
import UnliftIO.Async
import UnliftIO.Exception
import UnliftIO.MVar


getOnDemand :: forall m a. (
  MonadUnliftIO m, MonadLogger m
  ) => MVar (OnDemand a) -> m (Either Text a) -> m a
getOnDemand onDemandVar doObtain = do
  result <- modifyMVar onDemandVar $ \case
    OnDemandErrored msg -> expectationFailure (T.unpack msg)
    OnDemandNotStarted -> do
      asy <- async $ do
        let handler :: SomeException -> m a
            handler e = do
              modifyMVar_ onDemandVar (const $ return $ OnDemandErrored [i|Got exception: #{e}|])
              throwIO e

        handle handler $ do
          doObtain >>= \case
            Left err -> do
              modifyMVar_ onDemandVar (const $ return $ OnDemandErrored err)
              expectationFailure [i|Failed to obtain: #{err}|]

            Right x -> do
              modifyMVar_ onDemandVar (const $ return $ OnDemandReady x)
              return x

      return (OnDemandInProgress asy, Left asy)

    od@(OnDemandInProgress asy) -> pure (od, Left asy)
    od@(OnDemandReady x) -> pure (od, Right x)

  case result of
    Right x -> pure x
    Left asy -> wait asy