在 reflex-dom 中通过 websockets 检测关闭的服务器连接?

Detect a closed server connection via websockets in reflex-dom?

我一直在使用 reflex 和 reflex-dom 来重新创建棋盘游戏的网络版本,到目前为止我非常喜欢它,但是我需要一个 websocket 来提醒玩家当其他玩家有行动了。

一切正常,但如果服务器出现故障,我无法找到检测它发生并重新连接的方法。此外,如果您在服务器关闭时向服务器发送事件,它只会被吃掉而不会出现任何错误。

我正在使用来自 https://github.com/reflex-frp/reflex-examples/blob/master/websocket-echo/src/Main.hs

的精简版 websockets 示例
{-# LANGUAGE RecursiveDo #-}
module Lib where

import Data.Monoid 
import Reflex.Dom
import qualified Data.Text as T
import Data.Text.Encoding (encodeUtf8, decodeUtf8)


wsurl = "ws://127.0.0.1:5714"         
-- wsurl = "ws://echo.websocket.org"

someFunc = mainWidget $ do
  rec t <- textInput $ def & setValue .~ fmap (const "") newMessage
      b <- button "Send"
      text $ "Sending to " <> wsurl
      let newMessage = fmap ((:[]) . encodeUtf8 . T.pack) $ tag (current $ value t) $ leftmost [b, textInputGetEnter t]
  ws <- webSocket wsurl $ def & webSocketConfig_send .~ newMessage
  receivedMessages <- foldDyn (\m ms -> ms ++ [m]) [] $ _webSocket_recv ws
  el "p" $ text "Responses from :"
  _ <- el "ul" $ simpleList receivedMessages $ \m -> el "li" $ dynText =<< mapDyn (T.unpack . decodeUtf8) m
  return ()

我觉得应该有一种方法可以通过 tickLossy 发送超时的 ping,就像一些动态的 returns websockets 然后如果 ping 在一定时间内没有响应则重新连接?但是我无法想象重新连接的代码会是什么样子。

编辑:当 websocket 仍处于挂起状态时,反射 dom 发送事件是一个问题。我提出了拉取请求,尽管我觉得某处有更好的解决方案。

看起来像在关闭 websocket 时,库会尝试 reconnect:

  start = do
    ws <- liftIO $ newWebSocket wv url onMessage onOpen $ do
      void $ forkIO $ do --TODO: Is the fork necessary, or do event handlers run in their own threads automatically?
        liftIO $ writeIORef currentSocketRef Nothing
        liftIO $ threadDelay 1000000
        start
    liftIO $ writeIORef currentSocketRef $ Just ws
    return ()

(newWebSocket takes onClose 最后一个参数的事件处理程序)

您在重新连接时发送的所有消息是 ignored:

  performEvent_ $ ffor (_webSocketConfig_send config) $ \payloads -> forM_ payloads $ \payload -> do
    mws <- liftIO $ readIORef currentSocketRef
    case mws of
      Nothing -> return () -- Discard --TODO: should we do something better here? probably buffer it, since we handle reconnection logic; how do we verify that the server has received things?
      Just ws -> do
        liftIO $ webSocketSend ws payload

您可能应该在他们的问题跟踪器上打开一个问题。或者只是找到更好的图书馆。

Edit: It was an issue with reflex-dom sending an event while a websocket was still in the pending state. I made a pull request, although I feel there is a better solution somewhere.

仅供参考,自问题发布以来,WebSocket API 的一些非常相关的扩展已合并到 reflex-dom:

我相信关闭事件正是您要找的。只是当时没有。