update the examples to show how to cleanup resources once user disconnects
This commit is contained in:
parent
9a59f0648c
commit
e6d2769408
@ -1,4 +1,4 @@
|
|||||||
{-# LANGUAGE QuasiQuotes, TemplateHaskell, TypeFamilies, OverloadedStrings #-}
|
{-# LANGUAGE QuasiQuotes, TemplateHaskell, TypeFamilies, OverloadedStrings, ScopedTypeVariables #-}
|
||||||
import Yesod.Core
|
import Yesod.Core
|
||||||
import Yesod.WebSockets
|
import Yesod.WebSockets
|
||||||
import qualified Data.Text.Lazy as TL
|
import qualified Data.Text.Lazy as TL
|
||||||
@ -11,8 +11,9 @@ import Data.Monoid ((<>))
|
|||||||
import Control.Concurrent.STM.Lifted
|
import Control.Concurrent.STM.Lifted
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
import qualified Data.Map as M
|
import qualified Data.Map as M
|
||||||
|
import UnliftIO.Exception (try, SomeException)
|
||||||
|
|
||||||
data App = App (TVar (M.Map Text (TChan Text)))
|
data App = App (TVar (M.Map Text (TChan Text, Int)))
|
||||||
|
|
||||||
instance Yesod App
|
instance Yesod App
|
||||||
|
|
||||||
@ -20,6 +21,15 @@ mkYesod "App" [parseRoutes|
|
|||||||
/ HomeR GET
|
/ HomeR GET
|
||||||
|]
|
|]
|
||||||
|
|
||||||
|
cleanupChannel :: (Eq a1, Num a1) => Maybe (a2, a1) -> Maybe (a2, a1)
|
||||||
|
cleanupChannel Nothing = Nothing
|
||||||
|
cleanupChannel (Just (writeChan, 1)) = Nothing
|
||||||
|
cleanupChannel (Just c) = Just c
|
||||||
|
|
||||||
|
userJoinedChannel :: Num b => Maybe (a, b) -> Maybe (a, b)
|
||||||
|
userJoinedChannel Nothing = Nothing
|
||||||
|
userJoinedChannel (Just (writeChan, numUsers)) = Just (writeChan, numUsers + 1)
|
||||||
|
|
||||||
chatApp :: WebSocketsT Handler ()
|
chatApp :: WebSocketsT Handler ()
|
||||||
chatApp = do
|
chatApp = do
|
||||||
sendTextData ("Welcome to the chat server, please enter your name." :: Text)
|
sendTextData ("Welcome to the chat server, please enter your name." :: Text)
|
||||||
@ -37,18 +47,28 @@ chatApp = do
|
|||||||
writeChan <- atomically $ case maybeChan of
|
writeChan <- atomically $ case maybeChan of
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
chan <- newBroadcastTChan
|
chan <- newBroadcastTChan
|
||||||
writeTVar channelMapTVar $ M.insert channelId chan channelMap
|
writeTVar channelMapTVar $ M.insert channelId (chan, 1) channelMap
|
||||||
return chan
|
return chan
|
||||||
Just writeChan -> return writeChan
|
Just (writeChan, _) -> do
|
||||||
|
writeTVar channelMapTVar $ M.alter userJoinedChannel channelId channelMap
|
||||||
|
return writeChan
|
||||||
|
|
||||||
readChan <- atomically $ do
|
readChan <- atomically $ do
|
||||||
writeTChan writeChan $ name <> " has joined the chat"
|
writeTChan writeChan $ name <> " has joined the chat"
|
||||||
dupTChan writeChan
|
dupTChan writeChan
|
||||||
race_
|
(e :: Either SomeException ()) <- try $ race_
|
||||||
(forever $ atomically (readTChan readChan) >>= sendTextData)
|
(forever $ atomically (readTChan readChan) >>= sendTextData)
|
||||||
(sourceWS $$ mapM_C (\msg ->
|
(sourceWS $$ mapM_C (\msg ->
|
||||||
atomically $ writeTChan writeChan $ name <> ": " <> msg))
|
atomically $ writeTChan writeChan $ name <> ": " <> msg))
|
||||||
|
|
||||||
|
atomically $ case e of
|
||||||
|
Left _ -> do
|
||||||
|
-- clean up your resources when user disconnects here
|
||||||
|
let newChannelMap = M.alter cleanupChannel channelId channelMap
|
||||||
|
writeTVar channelMapTVar newChannelMap
|
||||||
|
writeTChan writeChan $ name <> " has left the chat"
|
||||||
|
Right () -> return ()
|
||||||
|
|
||||||
getHomeR :: Handler Html
|
getHomeR :: Handler Html
|
||||||
getHomeR = do
|
getHomeR = do
|
||||||
webSockets chatApp
|
webSockets chatApp
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
{-# LANGUAGE QuasiQuotes, TemplateHaskell, TypeFamilies, OverloadedStrings #-}
|
{-# LANGUAGE QuasiQuotes, TemplateHaskell, TypeFamilies, OverloadedStrings, ScopedTypeVariables #-}
|
||||||
import Yesod.Core
|
import Yesod.Core
|
||||||
import Yesod.WebSockets
|
import Yesod.WebSockets
|
||||||
import qualified Data.Text.Lazy as TL
|
import qualified Data.Text.Lazy as TL
|
||||||
@ -10,6 +10,7 @@ import Conduit
|
|||||||
import Data.Monoid ((<>))
|
import Data.Monoid ((<>))
|
||||||
import Control.Concurrent.STM.Lifted
|
import Control.Concurrent.STM.Lifted
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
|
import UnliftIO.Exception (try, SomeException)
|
||||||
|
|
||||||
data App = App (TChan Text)
|
data App = App (TChan Text)
|
||||||
|
|
||||||
@ -28,11 +29,15 @@ chatApp = do
|
|||||||
readChan <- atomically $ do
|
readChan <- atomically $ do
|
||||||
writeTChan writeChan $ name <> " has joined the chat"
|
writeTChan writeChan $ name <> " has joined the chat"
|
||||||
dupTChan writeChan
|
dupTChan writeChan
|
||||||
race_
|
(e :: Either SomeException ()) <- try $ race_
|
||||||
(forever $ atomically (readTChan readChan) >>= sendTextData)
|
(forever $ atomically (readTChan readChan) >>= sendTextData)
|
||||||
(sourceWS $$ mapM_C (\msg ->
|
(sourceWS $$ mapM_C (\msg ->
|
||||||
atomically $ writeTChan writeChan $ name <> ": " <> msg))
|
atomically $ writeTChan writeChan $ name <> ": " <> msg))
|
||||||
|
|
||||||
|
atomically $ case e of
|
||||||
|
Left _ -> writeTChan writeChan $ name <> " has left the chat"
|
||||||
|
Right () -> return ()
|
||||||
|
|
||||||
getHomeR :: Handler Html
|
getHomeR :: Handler Html
|
||||||
getHomeR = do
|
getHomeR = do
|
||||||
webSockets chatApp
|
webSockets chatApp
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
{-# LANGUAGE QuasiQuotes, TemplateHaskell, TypeFamilies, OverloadedStrings #-}
|
{-# LANGUAGE QuasiQuotes, TemplateHaskell, TypeFamilies, OverloadedStrings, ScopedTypeVariables #-}
|
||||||
import Yesod.Core
|
import Yesod.Core
|
||||||
import Yesod.WebSockets
|
import Yesod.WebSockets
|
||||||
import qualified Data.Text.Lazy as TL
|
import qualified Data.Text.Lazy as TL
|
||||||
@ -10,6 +10,7 @@ import Conduit
|
|||||||
import Data.Monoid ((<>))
|
import Data.Monoid ((<>))
|
||||||
import Control.Concurrent.STM.Lifted
|
import Control.Concurrent.STM.Lifted
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
|
import UnliftIO.Exception (try, SomeException)
|
||||||
|
|
||||||
data App = App (TChan Text)
|
data App = App (TChan Text)
|
||||||
|
|
||||||
@ -28,11 +29,15 @@ chatApp = do
|
|||||||
readChan <- atomically $ do
|
readChan <- atomically $ do
|
||||||
writeTChan writeChan $ name <> " has joined the chat"
|
writeTChan writeChan $ name <> " has joined the chat"
|
||||||
dupTChan writeChan
|
dupTChan writeChan
|
||||||
race_
|
(e :: Either SomeException ()) <- try $ race_
|
||||||
(forever $ atomically (readTChan readChan) >>= sendTextData)
|
(forever $ atomically (readTChan readChan) >>= sendTextData)
|
||||||
(sourceWS $$ mapM_C (\msg ->
|
(sourceWS $$ mapM_C (\msg ->
|
||||||
atomically $ writeTChan writeChan $ name <> ": " <> msg))
|
atomically $ writeTChan writeChan $ name <> ": " <> msg))
|
||||||
|
|
||||||
|
atomically $ case e of
|
||||||
|
Left _ -> writeTChan writeChan $ name <> " has left the chat"
|
||||||
|
Right () -> return ()
|
||||||
|
|
||||||
getHomeR :: Handler Html
|
getHomeR :: Handler Html
|
||||||
getHomeR = do
|
getHomeR = do
|
||||||
webSockets chatApp
|
webSockets chatApp
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user