How do you conditionally wrap an IO action in a given thread depending on some mutable state stored in an MVar?
My overall aim is to enable timeouts so that in a given game if a player does not send an action to the server within 30 seconds then the socket msg callback will be called with a special Timeout action to denote failure of the player to act.
I am looking for a method to enable each socket thread to subscribe to a change in game state contained in an MVar.
My current draft implementation for creating a Timeout action is as follows:
-- This function processes msgs from authenticated clients
authenticatedMsgLoop ::
(MsgIn -> ReaderT MsgHandlerConfig (ExceptT Err IO) ())
-> MsgHandlerConfig
-> IO ()
authenticatedMsgLoop msgCallback msgHandlerConfig@MsgHandlerConfig {..}
= do
finally
(forever $ do
maybeMsg <- timeout 1000000 (WS.receiveData clientConn)
let parsedMsg = maybe (Just Timeout) parseMsgFromJSON maybeMsg
for_ parsedMsg $ \parsedMsg -> do
result <-
runExceptT $ runReaderT (msgCallback parsedMsg) msgHandlerConfig
either (\err -> sendMsg clientConn $ ErrMsg err) return result)
return ())
(removeClient username serverState)
To summarise all msgs which are valid are passed to the msgCallback function. This callback will then update the card game with the new player action and then broadcast the new game state to all clients who are subscribed to the game.
One issue with this is that as soon as a timeout occurs an exception is thrown inside the thread which disconnects the running socket. This is of course undesirable behaviour.
Another issue is that this timeout is implemented after a new msg is received by a client. Instead I would like to the timeout to only be implemented when the game is in a particular state - that is a state in which the player represented by this particular thread is the next player to act.
Therefore the timeout for a player action in a particular game can only be enacted in at most one thread at at the same time. As the card game employs turn based action.
It follows that I need to conditionally wrap the IO action for receiving messages with a timeout depending on the game state which is stored within an MVar.