首页 > 解决方案 > 处理 yesod-websockets 中的断开连接

问题描述

我正在尝试让 yesod-websockets 与我的引导式基于 postgresql 的 yesod 应用程序一起工作。websocket 应该作为 postgres 表的实时更新,因此我需要维护一个包含已连接客户端列表及其 userId 的状态。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))

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

标签: haskellwebsocketyesod

解决方案


感谢 Chris Stryczynski 的评论,我能够通过 catch 处理程序解决它。

在客户端断开连接后进行清理的示例回显服务器可能如下所示:

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 ()
            )

推荐阅读