Обнаружить закрытое соединение с сервером через веб-сокеты в reflex-dom?

Я использовал reflex и reflex-dom для воссоздания веб-версии настольной игры, и мне это до сих пор нравится, но мне требуется веб-розетка, чтобы предупредить игрока, когда другой игрок сделал ход.

Все работает отлично, но если сервер выходит из строя, я не могу найти способ обнаружить, что это произошло, и восстановить соединение. Кроме того, если вы отправляете событие на сервер, когда оно не работает, оно просто съедается без ошибок.

Я использую урезанную версию примера websockets от https://github.com/reflex-frp/reflex-examples/blob/master/websocket-echo/src/Main.hs

{-# 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 для отправки пингов с тайм-аутом, как какая-то динамика, которая возвращает веб-сокеты, а затем повторно подключается, если пинг проходит определенное количество времени без ответа? Но мне трудно представить, как будет выглядеть код для повторного подключения.

Редактировать: это была проблема с reflex-dom, отправляющим событие, пока веб-сокет все еще находился в состоянии ожидания. Я сделал запрос извлечения, хотя я чувствую, что где-то есть лучшее решение.

2 ответа

Решение

Редактировать: это была проблема с reflex-dom, отправляющим событие, пока веб-сокет все еще находился в состоянии ожидания. Я сделал запрос извлечения, хотя я чувствую, что где-то есть лучшее решение.

Только к вашему сведению, с тех пор, как вопрос был опубликован, в API WebSocket были объединены некоторые весьма важные расширения: reflex-dom:

  • Вы можете закрыть веб-сокеты через Event с, см _webSocketConfig_close
  • Вы можете указать, хотите ли вы автоматически переподключиться, см. _webSocketConfig_reconnect
  • есть Event выставлено, когда соединение закрыто, см. _webSocket_close
  • есть Event для того, когда возникает ошибка, см. _webSocket_error

Я полагаю, что это именно то, что вы искали. Это было просто не доступно в то время.

Похоже на то, когда websocket закрывается, библиотека пытается восстановить соединение:

  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 принимает onClose обработчик события в последнем аргументе)

И все сообщения, которые вы отправляете при переподключении, игнорируются:

  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

Вы, вероятно, должны открыть проблему на их трекере. Или просто найдите лучшую библиотеку.

Другие вопросы по тегам