{-|
  Module      : Auth.Biscuit.Timer
  Copyright   : © Clément Delafargue, 2021
  License     : MIT
  Maintainer  : clement@delafargue.name
  Helper function making sure an IO action runs in an alloted time
-}
module Auth.Biscuit.Timer
  ( timer
  ) where

import           Control.Concurrent       (threadDelay)
import           Control.Concurrent.Async (race)

-- | Given a maximum execution time, run the provide action, and
-- fail (by returning `Nothing`) if it takes too much time.
-- Else, the action result is returned in a `Just`
timer :: Int
      -> IO a
      -> IO (Maybe a)
timer :: forall a. Int -> IO a -> IO (Maybe a)
timer Int
timeout IO a
job = do
  let watchDog :: IO ()
watchDog = Int -> IO ()
threadDelay Int
timeout
  Either () a
result <- IO () -> IO a -> IO (Either () a)
forall a b. IO a -> IO b -> IO (Either a b)
race IO ()
watchDog IO a
job
  Maybe a -> IO (Maybe a)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe a -> IO (Maybe a)) -> Maybe a -> IO (Maybe a)
forall a b. (a -> b) -> a -> b
$ case Either () a
result of
    Left ()
_  -> Maybe a
forall a. Maybe a
Nothing
    Right a
a -> a -> Maybe a
forall a. a -> Maybe a
Just a
a