Keep state in monad

This commit is contained in:
qvalentin 2023-02-18 18:25:38 +01:00
parent 01df3f1068
commit 5d3dced6f7
2 changed files with 124 additions and 59 deletions

View File

@ -0,0 +1,89 @@
module State.ConnectedClientsState
( MonadConnectedClientsModify (..),
MonadConnectedClientsRead (..),
addWSClientGeneric,
updateWSClientGeneric,
removeWSClientGeneric,
getConnctedClientsGeneric,
)
where
import ClassyPrelude
import Data.UUID
import Types.AppTypes
import Types.ConnectionState
class Monad m => MonadConnectedClientsModify m where
addWSClient :: Client -> m ()
removeWSClient :: UUID -> m ()
updateWSClient :: UUID -> (Client -> Client) -> m ()
addWSClientGeneric ::
( HasConnectedClientState env,
MonadReader env m,
MonadUnliftIO m
) =>
Client ->
m ()
addWSClientGeneric client = do
modifyState $ addClient client
addClient :: Client -> ConnectedClients -> ConnectedClients
addClient client clients = client : clients
updateWSClientGeneric ::
( HasConnectedClientState env,
MonadReader env m,
MonadUnliftIO m
) =>
UUID ->
(Client -> Client) ->
m
()
updateWSClientGeneric clientId patchFunction = do
modifyState $ updateClient clientId patchFunction
updateClient :: UUID -> (Client -> Client) -> ConnectedClients -> ConnectedClients
updateClient toUpdate f allClients = do
client <- allClients
if toUpdate == uuid client
then return $ f client
else return client
removeWSClientGeneric ::
( HasConnectedClientState env,
MonadReader env m,
MonadUnliftIO m
) =>
UUID ->
m ()
removeWSClientGeneric clientId = do
modifyState $ removeClient clientId
removeClient :: UUID -> ConnectedClients -> ConnectedClients
removeClient toRemove = filter ((/= toRemove) . uuid)
modifyState ::
( HasConnectedClientState env,
MonadReader env m,
MonadUnliftIO m
) =>
(ConnectedClients -> ConnectedClients) ->
m ()
modifyState modifyFunc = do
state <- getConnectedClientState <$> ask
modifyMVar_ state $ \s ->
let s' = modifyFunc s
in return s'
class Monad m => MonadConnectedClientsRead m where
getConnctedClients :: m ConnectedClients
getConnctedClientsGeneric ::
( HasConnectedClientState env,
MonadReader env m,
MonadUnliftIO m
) =>
m ConnectedClients
getConnctedClientsGeneric = do
ask >>= readMVar . getConnectedClientState

View File

@ -11,6 +11,14 @@ import Data.Aeson
import Data.UUID (UUID) import Data.UUID (UUID)
import Data.UUID.V4 (nextRandom) import Data.UUID.V4 (nextRandom)
import Network.WebSockets qualified as WS import Network.WebSockets qualified as WS
import State.ConnectedClientsState
( MonadConnectedClientsModify (..),
MonadConnectedClientsRead (getConnctedClients),
addWSClientGeneric,
getConnctedClientsGeneric,
removeWSClientGeneric,
updateWSClientGeneric,
)
import Types.AppTypes import Types.AppTypes
( Env (..), ( Env (..),
HasConnectedClientState (getConnectedClientState), HasConnectedClientState (getConnectedClientState),
@ -45,75 +53,36 @@ instance HasWSEnv WSEnv where
getConn = connection getConn = connection
getClientId = clientId getClientId = clientId
addWSClient ::
( HasConnectedClientState env,
MonadReader env m,
MonadUnliftIO m
) =>
Client ->
m ()
addWSClient client = do
state <- getConnectedClientState <$> ask
modifyMVar_ state $ \s -> do
let s' = addClient client s
return s'
addClient :: Client -> ConnectedClients -> ConnectedClients
addClient client clients = client : clients
disconnectWsClient ::
( HasWSEnv env,
HasConnectedClientState env,
MonadReader env m,
MonadUnliftIO m
) =>
m ()
disconnectWsClient = do
clientId <- getClientId <$> ask
state <- getConnectedClientState <$> ask
modifyMVar_ state $ \s ->
let s' = removeClient clientId s
in return s'
joinRoom :: joinRoom ::
( HasWSEnv env, ( MonadReader env m,
HasConnectedClientState env, MonadConnectedClientsModify m,
MonadReader env m, HasWSEnv env
MonadUnliftIO m
) => ) =>
m () m ()
joinRoom = do joinRoom = do
clientId <- getClientId <$> ask clientId <- getClientId <$> ask
state <- getConnectedClientState <$> ask updateWSClient clientId (\c -> c {joinedRoom = True})
liftIO $ putStrLn "joinedRoom"
modifyMVar_ state $ \s ->
let s' = updateClient clientId (\c -> c {joinedRoom = True}) s
in return s'
updateClientName :: updateClientName ::
( HasWSEnv env, ( HasWSEnv env,
HasConnectedClientState env,
MonadReader env m, MonadReader env m,
MonadUnliftIO m MonadConnectedClientsModify m
) => ) =>
SetClientInfo -> SetClientInfo ->
m () m ()
updateClientName clientInfo = do updateClientName clientInfo = do
clientId <- getClientId <$> ask clientId <- getClientId <$> ask
state <- getConnectedClientState <$> ask updateWSClient clientId (\c -> c {name = displayName clientInfo})
modifyMVar_ state $ \s ->
let s' = updateClient clientId (\c -> c {name = displayName clientInfo}) s
in return s'
removeClient :: UUID -> ConnectedClients -> ConnectedClients disconnectWsClient ::
removeClient toRemove = filter ((/= toRemove) . uuid) ( HasWSEnv env,
MonadConnectedClientsModify m,
updateClient :: UUID -> (Client -> Client) -> ConnectedClients -> ConnectedClients MonadReader env m
updateClient toUpdate f allClients = do ) =>
client <- allClients m ()
if toUpdate == uuid client disconnectWsClient = do
then return $ f client clientId <- getClientId <$> ask
else return client removeWSClient clientId
runWebSocketServer :: runWebSocketServer ::
( MonadIO m, ( MonadIO m,
@ -174,13 +143,22 @@ instance MonadWebSocket (WSApp WSEnv) where
sendMessage $ "Bad message: " <> pack err sendMessage $ "Bad message: " <> pack err
getTypedWSMessage getTypedWSMessage
instance MonadConnectedClientsModify (WSApp WSEnv) where
addWSClient = addWSClientGeneric
updateWSClient = updateWSClientGeneric
removeWSClient = removeWSClientGeneric
instance MonadConnectedClientsRead (WSApp WSEnv) where
getConnctedClients = getConnctedClientsGeneric
wsApp :: wsApp ::
( HasWSEnv env, ( HasWSEnv env,
HasConnectedClientState env, HasConnectedClientState env,
HasRoomsState env, HasRoomsState env,
MonadReader env m, MonadReader env m,
MonadUnliftIO m, MonadUnliftIO m,
MonadWebSocket m MonadWebSocket m,
MonadConnectedClientsModify m
) => ) =>
m () m ()
wsApp = do wsApp = do
@ -195,11 +173,9 @@ wsApp = do
handleWSAction :: handleWSAction ::
( HasWSEnv env, ( HasWSEnv env,
HasConnectedClientState env,
HasRoomsState env,
MonadReader env m, MonadReader env m,
MonadUnliftIO m, MonadWebSocket m,
MonadWebSocket m MonadConnectedClientsModify m
) => ) =>
m () m ()
handleWSAction = do handleWSAction = do