2018-05-11 12:31:53 +02:00
|
|
|
{-# LANGUAGE NamedFieldPuns #-}
|
|
|
|
module App (
|
|
|
|
T
|
|
|
|
, Context(..)
|
|
|
|
, connection
|
|
|
|
, debug
|
|
|
|
, get
|
|
|
|
, current
|
|
|
|
, server
|
|
|
|
, try
|
|
|
|
, update
|
|
|
|
, update_
|
|
|
|
) where
|
|
|
|
|
|
|
|
import Control.Concurrent (MVar, modifyMVar, putMVar, readMVar, takeMVar)
|
|
|
|
import Control.Monad.Reader (ReaderT(..), ask, asks, lift)
|
2019-10-13 22:00:35 +02:00
|
|
|
import Data.Map ((!))
|
2019-08-24 23:29:40 +02:00
|
|
|
import Hanafuda.KoiKoi (PlayerID)
|
2019-10-13 22:00:35 +02:00
|
|
|
import Network.WebSockets (Connection)
|
2018-05-11 12:31:53 +02:00
|
|
|
import qualified Server (T(..))
|
2019-10-13 22:00:35 +02:00
|
|
|
import qualified Session (T(..))
|
2018-05-11 12:31:53 +02:00
|
|
|
|
|
|
|
data Context = Context {
|
|
|
|
mServer :: MVar Server.T
|
2019-08-24 23:29:40 +02:00
|
|
|
, playerID :: PlayerID
|
2018-05-11 12:31:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
type T a = ReaderT Context IO a
|
|
|
|
|
|
|
|
server :: T Server.T
|
|
|
|
server = asks mServer >>= lift . readMVar
|
|
|
|
|
2019-08-24 23:29:40 +02:00
|
|
|
get :: PlayerID -> T Session.T
|
|
|
|
get playerID =
|
|
|
|
(! playerID) . Server.sessions <$> server
|
2018-05-11 12:31:53 +02:00
|
|
|
|
|
|
|
current :: T Session.T
|
|
|
|
current = do
|
2019-08-24 23:29:40 +02:00
|
|
|
asks playerID >>= get
|
2018-05-11 12:31:53 +02:00
|
|
|
|
|
|
|
connection :: T Connection
|
|
|
|
connection = Session.connection <$> current
|
|
|
|
|
|
|
|
debug :: String -> T ()
|
|
|
|
debug message =
|
2019-08-24 23:29:40 +02:00
|
|
|
show <$> asks playerID
|
2018-05-11 12:31:53 +02:00
|
|
|
>>= lift . putStrLn . (++ ' ':message)
|
|
|
|
|
|
|
|
try :: (Server.T -> Either String Server.T) -> T (Maybe String)
|
|
|
|
try f = do
|
|
|
|
Context {mServer} <- ask
|
|
|
|
currentValue <- lift $ takeMVar mServer
|
|
|
|
lift $ case f currentValue of
|
|
|
|
Left message -> putMVar mServer currentValue >> return (Just message)
|
|
|
|
Right updated -> putMVar mServer updated >> return Nothing
|
|
|
|
|
|
|
|
{- Not using the previous to minimize the duration mServer gets locked -}
|
|
|
|
update :: (Server.T -> (Server.T, a)) -> T a
|
|
|
|
update f = do
|
|
|
|
Context {mServer} <- ask
|
|
|
|
lift $ modifyMVar mServer (return . f)
|
|
|
|
|
|
|
|
update_ :: (Server.T -> Server.T) -> T ()
|
|
|
|
update_ f = update $ (\x -> (x, ())) . f
|