haskellreflex

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


I've been using reflex and reflex-dom to recreate a web version of a boardgame, and I quite like it so far, but I require a websocket to alert a player when the other player has made a move.

Everything works great but if the server goes down, I can't find a way to detect that it happened and reconnect. Additionally, if you send an event to a server while it is down, it is just is eaten up without any error.

I'm using a stripped down version of the websockets example from 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 ()

I feel like there should be a way to do this with tickLossy to send pings with timeout, like some dynamic which returns websockets and then reconnects if a ping goes a certain amount of time without a response? But I'm having trouble envisioning what the code to reconnect would look like.

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.


Solution

  • 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.

    Just FYI, since the question was posted there have been some quite relevant extensions to the WebSocket API merged into reflex-dom:

    I believe the close event is exactly what you were looking for. It was just not available at the time.