module Server.ResponseController
( ResponseController
, new
, dispatch
, setCheckpointAndWait
) where
import Control.Concurrent
import Control.Concurrent.SizedChan
import Control.Monad ( void
, when
)
import Data.IORef
data ResponseController = ResponseController
{
ResponseController -> IORef Int
dispatchedCount :: IORef Int
,
ResponseController -> IORef Int
completedCount :: IORef Int
,
ResponseController -> SizedChan Checkpoint
checkpointChan :: SizedChan Checkpoint
}
type Checkpoint = (Int, () -> IO ())
new :: IO ResponseController
new :: IO ResponseController
new = IORef Int
-> IORef Int -> SizedChan Checkpoint -> ResponseController
ResponseController (IORef Int
-> IORef Int -> SizedChan Checkpoint -> ResponseController)
-> IO (IORef Int)
-> IO (IORef Int -> SizedChan Checkpoint -> ResponseController)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Int -> IO (IORef Int)
forall a. a -> IO (IORef a)
newIORef Int
0 IO (IORef Int -> SizedChan Checkpoint -> ResponseController)
-> IO (IORef Int)
-> IO (SizedChan Checkpoint -> ResponseController)
forall a b. IO (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Int -> IO (IORef Int)
forall a. a -> IO (IORef a)
newIORef Int
0 IO (SizedChan Checkpoint -> ResponseController)
-> IO (SizedChan Checkpoint) -> IO ResponseController
forall a b. IO (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> IO (SizedChan Checkpoint)
forall a. IO (SizedChan a)
newSizedChan
dispatch :: ResponseController -> IO (() -> IO ())
dispatch :: ResponseController -> IO (() -> IO ())
dispatch ResponseController
controller = do
IORef Int -> (Int -> Int) -> IO ()
forall a. IORef a -> (a -> a) -> IO ()
modifyIORef' (ResponseController -> IORef Int
dispatchedCount ResponseController
controller) Int -> Int
forall a. Enum a => a -> a
succ
(() -> IO ()) -> IO (() -> IO ())
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ((() -> IO ()) -> IO (() -> IO ()))
-> (() -> IO ()) -> IO (() -> IO ())
forall a b. (a -> b) -> a -> b
$ \() -> do
IORef Int -> (Int -> Int) -> IO ()
forall a. IORef a -> (a -> a) -> IO ()
modifyIORef' (ResponseController -> IORef Int
completedCount ResponseController
controller) Int -> Int
forall a. Enum a => a -> a
succ
Maybe Checkpoint
result <- SizedChan Checkpoint -> IO (Maybe Checkpoint)
forall a. SizedChan a -> IO (Maybe a)
tryPeekSizedChan (ResponseController -> SizedChan Checkpoint
checkpointChan ResponseController
controller)
case Maybe Checkpoint
result of
Maybe Checkpoint
Nothing -> () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
Just (Int
dispatched, () -> IO ()
callback) -> do
Int
completed <- IORef Int -> IO Int
forall a. IORef a -> IO a
readIORef (ResponseController -> IORef Int
completedCount ResponseController
controller)
Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Int
dispatched Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
completed) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
() -> IO ()
callback ()
IO Checkpoint -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO Checkpoint -> IO ()) -> IO Checkpoint -> IO ()
forall a b. (a -> b) -> a -> b
$ SizedChan Checkpoint -> IO Checkpoint
forall a. SizedChan a -> IO a
readSizedChan (ResponseController -> SizedChan Checkpoint
checkpointChan ResponseController
controller)
setCheckpoint :: ResponseController -> (() -> IO ()) -> IO ()
setCheckpoint :: ResponseController -> (() -> IO ()) -> IO ()
setCheckpoint ResponseController
controller () -> IO ()
callback = do
Int
dispatched <- IORef Int -> IO Int
forall a. IORef a -> IO a
readIORef (ResponseController -> IORef Int
dispatchedCount ResponseController
controller)
Int
completed <- IORef Int -> IO Int
forall a. IORef a -> IO a
readIORef (ResponseController -> IORef Int
completedCount ResponseController
controller)
if Int
dispatched Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
completed
then () -> IO ()
callback ()
else do
let checkpoint :: Checkpoint
checkpoint = (Int
dispatched, () -> IO ()
callback)
SizedChan Checkpoint -> Checkpoint -> IO ()
forall a. SizedChan a -> a -> IO ()
writeSizedChan (ResponseController -> SizedChan Checkpoint
checkpointChan ResponseController
controller) Checkpoint
checkpoint
setCheckpointAndWait :: ResponseController -> IO ()
setCheckpointAndWait :: ResponseController -> IO ()
setCheckpointAndWait ResponseController
controller = do
MVar ()
mvar <- IO (MVar ())
forall a. IO (MVar a)
newEmptyMVar
ResponseController -> (() -> IO ()) -> IO ()
setCheckpoint ResponseController
controller (MVar () -> () -> IO ()
forall a. MVar a -> a -> IO ()
putMVar MVar ()
mvar)
MVar () -> IO ()
forall a. MVar a -> IO a
takeMVar MVar ()
mvar