@@ -44,14 +44,23 @@ import Data.Text
4444
4545data WebSocketConfig t a
4646 = WebSocketConfig { _webSocketConfig_send :: Event t [a]
47+ , _webSocketConfig_close :: Event t (Word, Text)
48+ , _webSocketConfig_reconnect :: Bool
4749 }
4850
4951instance Reflex t => Default (WebSocketConfig t a) where
50− def = WebSocketConfig never
52+ def = WebSocketConfig never never True
5153
5254data WebSocket t
5355 = WebSocket { _webSocket_recv :: Event t ByteString
5456 , _webSocket_open :: Event t ()
57+ , _webSocket_error :: Event t () -- eror event does not carry any data and is always
58+ -- followed by termination of the connection
59+ -- for details see the close event
60+ , _webSocket_close :: Event t ( Bool -- wasClean
61+ , Word -- code
62+ , Text -- reason
63+ )
5564 }
5665
5766-- This can be used to send either binary or text messages for the same websocket connection
@@ -65,25 +74,34 @@ webSocket url config = do
6574 wv <- fmap unWebViewSingleton askWebView
6675 (eRecv, onMessage) <- newTriggerEvent
6776 currentSocketRef <- liftIO $ newIORef Nothing
68− --TODO: Disconnect if value no longer needed
6977 (eOpen, triggerEOpen) <- newTriggerEventWithOnComplete
78+ (eError, triggerEError) <- newTriggerEvent
79+ (eClose, triggerEClose) <- newTriggerEvent
7080 payloadQueue <- liftIO newTQueueIO
7181 isOpen <- liftIO newEmptyTMVarIO
72− let onOpen = triggerEOpen () $ do
73− liftIO $ void $ atomically $ tryPutTMVar isOpen ()
74− --TODO: Is the fork necessary, or do event handlers run in their own threads automatically?
75− onClose = void $ forkIO $ do
76− _ <- liftIO $ atomically $ tryTakeTMVar isOpen
77− liftIO $ writeIORef currentSocketRef Nothing
78− liftIO $ threadDelay 1000000
79− start
82+ let onOpen = triggerEOpen () $ liftIO $ void $ atomically $ tryPutTMVar isOpen ()
83+ onError = triggerEError ()
84+ onClose args = do
85+ triggerEClose args
86+ --TODO: Is the fork necessary, or do event handlers run in their own threads automatically?
87+ void $ forkIO $ do
88+ _ <- liftIO $ atomically $ tryTakeTMVar isOpen
89+ liftIO $ writeIORef currentSocketRef Nothing
90+ when (_webSocketConfig_reconnect config) $ do
91+ liftIO $ threadDelay 1000000
92+ start
8093 start = do
81− ws <- liftIO $ newWebSocket wv url onMessage onOpen onClose
94+ ws <- liftIO $ newWebSocket wv url onMessage onOpen onError onClose
8295 liftIO $ writeIORef currentSocketRef $ Just ws
8396 return ()
8497 performEvent_ . (liftIO start <$) =<< getPostBuild
8598 performEvent_ $ ffor (_webSocketConfig_send config) $ \payloads -> forM_ payloads $ \payload ->
8699 liftIO $ atomically $ writeTQueue payloadQueue payload
100+ performEvent_ $ ffor (_webSocketConfig_close config) $ \(code,reason) -> liftIO $ do
101+ mws <- readIORef currentSocketRef
102+ case mws of
103+ Nothing -> return ()
104+ Just ws -> closeWebSocket ws (fromIntegral code) reason
87105
88106 _ <- liftIO $ forkIO $ forever $ do
89107 payload <- atomically $ do
@@ -98,6 +116,6 @@ webSocket url config = do
98116 `catch`
99117 (\(_ :: SomeException) -> return False))
100118 unless success $ atomically $ unGetTQueue payloadQueue payload
101− return $ WebSocket eRecv eOpen
119+ return $ WebSocket eRecv eOpen eError eClose
102120
103121makeLensesWith (lensRules & simpleLenses .~ True) ''WebSocketConfig