根据存储在MVar中的某种可变状态,如何在给定线程中有条件地包装IO操作?
我的总体目标是启用超时,以便在给定的游戏中,如果玩家在30秒内不向服务器发送动作,则套接字msg回调将被调用,并使用一个特殊的超时操作来表示玩家未能执行任务。
我正在寻找一种方法,使每个套接字线程订阅游戏状态的变化包含在一个MVar。
我当前创建超时操作的实现草案如下:
-- 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)
总之,所有有效的msg都传递给msgCallback函数。此回调将使用新玩家操作更新纸牌游戏,然后将新游戏状态广播给所有订阅该游戏的客户端。
其中一个问题是,一旦超时发生,就会在断开正在运行的套接字的线程中抛出异常。这当然是不可取的行为。
另一个问题是,这个超时是在客户端接收到新的msg之后实现的。相反,我希望只在游戏处于特定状态时才实现超时--这是一种状态,在这种状态中,由这个特定线程所代表的玩家是下一个要行动的玩家。
因此,特定游戏中玩家动作的超时只能同时在最多一个线程中执行。因为纸牌游戏采用基于回合的动作。
因此,我需要有条件地包装IO操作,以便根据存储在MVar中的游戏状态来接收超时消息。
https://stackoverflow.com/questions/51113460
复制