Broadcasting works

This commit is contained in:
qvalentin 2023-02-07 20:30:25 +01:00
parent 7c8394f0fd
commit b0ebeda23a
5 changed files with 58 additions and 54 deletions

View File

@ -1,8 +1,3 @@
{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}
{-# HLINT ignore "Redundant <$>" #-}
{-# HLINT ignore "Redundant $" #-}
{-# HLINT ignore "Redundant bracket" #-}
module BroadcastUserData module BroadcastUserData
( broadcastUserData, ( broadcastUserData,
) )
@ -10,11 +5,11 @@ where
import ClassyPrelude import ClassyPrelude
import Data.Aeson (encode) import Data.Aeson (encode)
import Network.WebSockets qualified as WS
import Types.AppTypes (HasConnectedClientState (..)) import Types.AppTypes (HasConnectedClientState (..))
import Types.ConnectionState (Client (..)) import Types.ConnectionState (Client (..), ConnectedClients)
import Types.RoomsState (HasRoomsState (..)) import Types.RoomsState (HasRoomsState (..))
import Types.UsersData (UsersData (..)) import Types.UsersData (UsersData (..))
import WebSocket (broadCastToClients)
broadcastUserData :: broadcastUserData ::
( MonadIO m, ( MonadIO m,
@ -24,9 +19,10 @@ broadcastUserData ::
) => ) =>
m () m ()
broadcastUserData = do broadcastUserData = do
putStrLn "broadcasting"
userWithOutRoom <- getUsersWithoutRoom userWithOutRoom <- getUsersWithoutRoom
roomsData <- (getRoomsState <$> ask) >>= readMVar roomsData <- ask >>= readMVar . getRoomsState
let usersData = UsersData {userWithOutRoom = userWithOutRoom, roomsData = roomsData} let usersData = UsersData {usersWithOutRoom = userWithOutRoom, roomsData = roomsData}
broadCastToClients $ (decodeUtf8 . toStrict . encode) usersData broadCastToClients $ (decodeUtf8 . toStrict . encode) usersData
getUsersWithoutRoom :: getUsersWithoutRoom ::
@ -36,5 +32,21 @@ getUsersWithoutRoom ::
) => ) =>
m [Text] m [Text]
getUsersWithoutRoom = do getUsersWithoutRoom = do
state <- (getConnectedClientState <$> ask) >>= readMVar state <- ask >>= readMVar . getConnectedClientState
return $ map name $ filter (not . joinedRoom) state return $ map name $ filter (not . joinedRoom) state
broadcast :: Text -> ConnectedClients -> IO ()
broadcast message clients = do
putStrLn message
forM_ clients $ \client -> WS.sendTextData (conn client) message
broadCastToClients ::
( MonadIO m,
HasConnectedClientState env,
MonadReader env m
) =>
Text ->
m ()
broadCastToClients message = do
state <- getConnectedClientState <$> ask
liftIO $ withMVar state $ \currenState -> broadcast message currenState

View File

@ -75,6 +75,7 @@ badRequest ::
m ResponseReceived m ResponseReceived
badRequest errorMessage = do badRequest errorMessage = do
respond' <- getRespond <$> ask respond' <- getRespond <$> ask
liftIO $ print errorMessage
liftIO $ liftIO $
respond' $ respond' $
responseLBS responseLBS

View File

@ -11,7 +11,7 @@ import Types.RoomData (RoomsData)
data UsersData = UsersData data UsersData = UsersData
{ roomsData :: RoomsData, { roomsData :: RoomsData,
userWithOutRoom :: UsersWithoutRoom usersWithOutRoom :: UsersWithoutRoom
} }
deriving (Generic, Show) deriving (Generic, Show)

View File

@ -22,7 +22,6 @@ import Types.RoomsState
updateRoomState, updateRoomState,
) )
import Types.WebEnv import Types.WebEnv
import WebSocket (broadCastToClients)
newtype ExceptTApp e a = E {unExceptTApp :: IO (Either e a)} newtype ExceptTApp e a = E {unExceptTApp :: IO (Either e a)}
deriving deriving

View File

@ -2,16 +2,19 @@
{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE UndecidableInstances #-}
module WebSocket (runWebSocketServer) where
module WebSocket (broadCastToClients, runWebSocketServer) where import BroadcastUserData (broadcastUserData)
import ClassyPrelude import ClassyPrelude
import Data.UUID (UUID) import Data.UUID (UUID)
import Data.UUID.V4 (nextRandom) import Data.UUID.V4 (nextRandom)
import qualified Network.WebSockets as WS import Network.WebSockets qualified as WS
import Types.AppTypes (Env (connectedClientsState), import Types.AppTypes
HasConnectedClientState (getConnectedClientState)) ( Env (..),
HasConnectedClientState (getConnectedClientState),
)
import Types.ConnectionState (Client (..), ConnectedClients) import Types.ConnectionState (Client (..), ConnectedClients)
import Types.RoomsState (HasRoomsState (..))
data WSEnv = WSEnv data WSEnv = WSEnv
{ appEnv :: Env, { appEnv :: Env,
@ -22,6 +25,9 @@ data WSEnv = WSEnv
instance HasConnectedClientState WSEnv where instance HasConnectedClientState WSEnv where
getConnectedClientState = connectedClientsState . appEnv getConnectedClientState = connectedClientsState . appEnv
instance HasRoomsState WSEnv where
getRoomsState = roomsState . appEnv
class HasWSEnv a where class HasWSEnv a where
getConn :: a -> WS.Connection getConn :: a -> WS.Connection
getClientId :: a -> UUID getClientId :: a -> UUID
@ -70,6 +76,7 @@ joinRoom ::
joinRoom = do joinRoom = do
clientId <- getClientId <$> ask clientId <- getClientId <$> ask
state <- getConnectedClientState <$> ask state <- getConnectedClientState <$> ask
liftIO $ putStrLn "joinedRoom"
modifyMVar_ state $ \s -> modifyMVar_ state $ \s ->
let s' = updateClient clientId (\c -> c {joinedRoom = True}) s let s' = updateClient clientId (\c -> c {joinedRoom = True}) s
in return s' in return s'
@ -80,15 +87,10 @@ removeClient toRemove = filter ((/= toRemove) . uuid)
updateClient :: UUID -> (Client -> Client) -> ConnectedClients -> ConnectedClients updateClient :: UUID -> (Client -> Client) -> ConnectedClients -> ConnectedClients
updateClient toUpdate f allClients = do updateClient toUpdate f allClients = do
client <- allClients client <- allClients
if (toUpdate == uuid client) if toUpdate == uuid client
then (return $ f client) then return $ f client
else return client else return client
broadcast :: Text -> ConnectedClients -> IO ()
broadcast message clients = do
putStrLn message
forM_ clients $ \client -> WS.sendTextData (conn client) message
runWebSocketServer :: runWebSocketServer ::
( MonadIO m, ( MonadIO m,
MonadReader Env m MonadReader Env m
@ -111,8 +113,7 @@ runWSApp = do
conn <- WS.acceptRequest pending conn <- WS.acceptRequest pending
uuid <- nextRandom uuid <- nextRandom
let wsEnv = WSEnv {appEnv = env, connection = conn, clientId = uuid} let wsEnv = WSEnv {appEnv = env, connection = conn, clientId = uuid}
WS.withPingThread conn 30 (return ()) $ do WS.withPingThread conn 30 (return ()) $ unWSApp wsApp wsEnv
unWSApp wsApp wsEnv
) )
newClient :: newClient ::
@ -140,6 +141,7 @@ newtype WSApp env a = WSApp {unWSApp :: env -> IO a}
wsApp :: wsApp ::
( HasWSEnv env, ( HasWSEnv env,
HasConnectedClientState env, HasConnectedClientState env,
HasRoomsState env,
MonadReader env m, MonadReader env m,
MonadUnliftIO m MonadUnliftIO m
) => ) =>
@ -149,10 +151,11 @@ wsApp = do
putStrLn msg putStrLn msg
client <- newClient msg client <- newClient msg
addWSClient client addWSClient client
flip finally disconnectWsClient $ do broadcastUserData
forever $ do flip finally disconnectWsClient $ forever $ do
currentMsg <- getMessage currentMsg <- getMessage
joinRoom joinRoom
broadcastUserData
putStrLn currentMsg putStrLn currentMsg
getMessage :: getMessage ::
@ -164,14 +167,3 @@ getMessage ::
getMessage = do getMessage = do
conn' <- getConn <$> ask conn' <- getConn <$> ask
liftIO $ WS.receiveData conn' liftIO $ WS.receiveData conn'
broadCastToClients ::
( MonadIO m,
HasConnectedClientState env,
MonadReader env m
) =>
Text ->
m ()
broadCastToClients message = do
state <- getConnectedClientState <$> ask
liftIO $ withMVar state $ \currenState -> broadcast message currenState