处理yesod-websockets中的断开连接

问题描述

我正在尝试使我的基于postgresql的yesod应用程序与yesod-websockets一起使用。 websocket应该充当postgres表的实时更新,因此我需要维护一个状态,其中包含连接的客户端及其用户ID的列表。 websocket断开连接后如何运行功能?从更大的角度看,应该使用此功能从状态列表中删除Websocket连接。

到目前为止我所拥有的:

type LobbyState = [(UserId,WS.Connection)]

addClient :: (UserId,WS.Connection) -> LobbyState -> LobbyState
addClient (userId,conn) state = (userId,conn) : state

chatApp :: UserId -> WebSocketsT Handler ()
chatApp userId = do
  conn <- ask
  -- connections is a MVar [(UserId,WS.Connection)]
  connections <- lobbyConnections <$> getYesod
  modifyMVar_ connections $ \s -> do
    let s' = addClient (userId,conn) s
    return s'
  -- how to wait for disconnect and execute a function?

getGameR :: Handler TypedContent
getGameR = do
  -- Todo: correct usage??
  userId <- requireAuthId
  webSockets $ chatApp userId
  -- some more normal HTML handler code

在示例中,他们使用以下代码段:

race_
        (forever $ atomically (readTChan readChan) >>= sendTextData)
        (sourceWS $$ mapM_C (\msg ->
            atomically $ writeTChan writeChan $ name <> ": " <> msg))

我了解如何利用TChan来永久发送更新,但是我如何对实际的断开事件做出反应以清理某些状态?

解决方法

由于Chris Stryczynski的评论,我能够通过捕获处理程序解决它。

在客户端断开连接后具有清理功能的示例回显服务器可能看起来像这样:

chatApp :: WebSocketsT Handler ()
chatApp =
  ( forever $ do
      msg :: Text <- receiveData
      sendTextData msg
  )
    `catch` ( \(e :: ConnectionException) -> do
                let eshow = fromString $ show e
                putStrLn $ eshow
                -- clean up specific state here
                case e of
                  CloseRequest code msg ->  -- Handle specific close codes/msg
                    return ()
            )