module Patat.AutoAdvance
( maybeAutoAdvance
, autoAdvance
) where
import Control.Concurrent (threadDelay)
import qualified Control.Concurrent.Async as Async
import qualified Control.Concurrent.Chan as Chan
import Control.Monad (forever)
import qualified Data.IORef as IORef
import Data.Time (diffUTCTime, getCurrentTime)
import Patat.Presentation (PresentationCommand (..))
maybeAutoAdvance
:: Maybe Int
-> Chan.Chan PresentationCommand
-> (Chan.Chan PresentationCommand -> IO a)
-> IO a
maybeAutoAdvance :: forall a.
Maybe Int
-> Chan PresentationCommand
-> (Chan PresentationCommand -> IO a)
-> IO a
maybeAutoAdvance Maybe Int
Nothing Chan PresentationCommand
chan Chan PresentationCommand -> IO a
f = Chan PresentationCommand -> IO a
f Chan PresentationCommand
chan
maybeAutoAdvance (Just Int
delaySeconds) Chan PresentationCommand
chan Chan PresentationCommand -> IO a
f = Int
-> Chan PresentationCommand
-> (Chan PresentationCommand -> IO a)
-> IO a
forall a.
Int
-> Chan PresentationCommand
-> (Chan PresentationCommand -> IO a)
-> IO a
autoAdvance Int
delaySeconds Chan PresentationCommand
chan Chan PresentationCommand -> IO a
f
autoAdvance
:: Int
-> Chan.Chan PresentationCommand
-> (Chan.Chan PresentationCommand -> IO a)
-> IO a
autoAdvance :: forall a.
Int
-> Chan PresentationCommand
-> (Chan PresentationCommand -> IO a)
-> IO a
autoAdvance Int
delaySeconds Chan PresentationCommand
existingChan Chan PresentationCommand -> IO a
f = do
let delay :: Int
delay = Int
delaySeconds Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
1000
newChan <- IO (Chan PresentationCommand)
forall a. IO (Chan a)
Chan.newChan
latestCommandAt <- IORef.newIORef =<< getCurrentTime
(forever $ do
cmd <- Chan.readChan existingChan
getCurrentTime >>= IORef.writeIORef latestCommandAt
Chan.writeChan newChan cmd) `Async.withAsync` \Async (ZonkAny 0)
_ ->
(IO () -> IO (ZonkAny 1)
forall (f :: * -> *) a b. Applicative f => f a -> f b
forever (IO () -> IO (ZonkAny 1)) -> IO () -> IO (ZonkAny 1)
forall a b. (a -> b) -> a -> b
$ do
current <- IO UTCTime
getCurrentTime
latest <- IORef.readIORef latestCommandAt
let elapsed = NominalDiffTime -> Int
forall b. Integral b => NominalDiffTime -> b
forall a b. (RealFrac a, Integral b) => a -> b
floor (NominalDiffTime -> Int) -> NominalDiffTime -> Int
forall a b. (a -> b) -> a -> b
$ NominalDiffTime
1000 NominalDiffTime -> NominalDiffTime -> NominalDiffTime
forall a. Num a => a -> a -> a
* (UTCTime
current UTCTime -> UTCTime -> NominalDiffTime
`diffUTCTime` UTCTime
latest) :: Int
if elapsed >= delay
then do
Chan.writeChan newChan Forward
IORef.writeIORef latestCommandAt current
threadDelay (delay * 1000)
else do
let wait = Int
delay Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
elapsed
threadDelay (wait * 1000)) IO (ZonkAny 1) -> (Async (ZonkAny 1) -> IO a) -> IO a
forall a b. IO a -> (Async a -> IO b) -> IO b
`Async.withAsync` \Async (ZonkAny 1)
_ ->
Chan PresentationCommand -> IO a
f Chan PresentationCommand
newChan