在 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:
- 您可以通过
Event
s 关闭 websockets,参见 _webSocketConfig_close
- 您可以指定是否要自动重新连接,请参阅
_webSocketConfig_reconnect
- 有一个
Event
在连接关闭时公开,请参阅 _webSocket_close
- 出现错误时会显示
Event
,请参阅 _webSocket_error
我相信关闭事件正是您要找的。只是当时没有。
我一直在使用 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:
- 您可以通过
Event
s 关闭 websockets,参见_webSocketConfig_close
- 您可以指定是否要自动重新连接,请参阅
_webSocketConfig_reconnect
- 有一个
Event
在连接关闭时公开,请参阅_webSocket_close
- 出现错误时会显示
Event
,请参阅_webSocket_error
我相信关闭事件正是您要找的。只是当时没有。