{-|
Module : Resources.Game
Description :
Copyright : (c) Alexander Vieth, 2015
Licence : BSD3
Maintainer : aovieth@gmail.com
Stability : experimental
Portability : non-portable (GHC only)
-}
{-# LANGUAGE AutoDeriveTypeable #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE StandaloneDeriving #-}
module Resources.Game (
resource
) where
import Control.Monad.Trans.Class
import Control.Monad.Trans.State as S
import Control.Monad.Trans.Reader
import Control.Monad.Trans.Except
import qualified Data.Map as M
import Data.Hourglass
import Rest
import Rest.Resource as R
import Rest.Dictionary.Types
import Types.Server
import Types.GameId
import Types.Credentials
import Types.GameState
import Resources.Game.Create as Create
import Resources.Game.Remove as Remove
import Diplomacy.Game
import Diplomacy.Turn
-- | The game resource will use a string identifier to pick out a game, and
-- give methods
-- GET : all info about the game state
-- GET : listing of the games
-- CREATE : make a new game
-- DELETE : destroy a game
-- TBD parameterize on the great power who's asking?!
-- Admin | Player GreatPower
-- Admin | Player String? Use player names rather than their power?
resource :: Resource Server (ReaderT GameId Server) GameId () Void
resource = mkResourceReader
{ R.name = "game"
, R.schema = withListing () $ unnamedSingle GameId
--, R.schema = withListing () $ named [("id", singleBy GameId)]
-- We use update (PUT) where we really ought to use get (GET) because
-- there is a lot of resistance against including bodies in GET requests,
-- so much so that the W3C XMLHttpRequest NEVER includes a body in a
-- GET request.
, R.update = Just get
-- TODO TBD listing doesn't work; unsupported route. Why?!?
, R.list = const listing
, R.create = Just create
, R.remove = Just remove
}
where
get :: Handler (ReaderT GameId Server)
get = secureHandler $ mkHandler (jsonO . jsonE . jsonI) handler
handler :: Env h p Credentials -> ExceptT (Reason Void) (ReaderT GameId Server) (Maybe GameData)
handler env =
let credentials = input env
in lift ask >>= \gameId -> doGet credentials gameId
doGet
:: Credentials
-> GameId
-> ExceptT (Reason Void) (ReaderT GameId Server) (Maybe GameData)
doGet credentials gameId = withUserCredentialsForGame credentials gameId f
where
f gameStateView = return $ do
metadata <- gameStateViewMetadata gameStateView
let turn = metadataTurn metadata
let round = metadataRound metadata
gameStateViewData turn round gameStateView
listing :: ListHandler Server
listing = mkListing (stringO) $ \_ -> lift doListing
doListing :: Server [String]
doListing = listGames >>= return . fmap show
create :: Handler Server
create = secureHandler $ mkInputHandler (jsonO . jsonE . jsonI) $ doCreate
doCreate :: CreateGameInput -> ExceptT (Reason Void) Server CreateGameOutput
doCreate input = withAdminCredentials creds (lift (createGame gameId password duration duration'))
where
creds = Create.credentials input
gameId = Create.gameId input
password = Create.gamePassword input
duration = maybe (makeDuration 15) makeDuration (Create.gameDuration input)
duration' = maybe (makeDuration 5) makeDuration (Create.gameSecondDuration input)
makeDuration x = Duration (fromIntegral 0) (fromIntegral x) (fromIntegral 0) (fromIntegral 0)
remove :: Handler (ReaderT GameId Server)
remove = secureHandler $ mkIdHandler (jsonO . jsonE . jsonI) $ \credentials gameId -> doRemove (RemoveGameInput gameId credentials)
doRemove :: RemoveGameInput -> ExceptT (Reason Void) (ReaderT GameId Server) RemoveGameOutput
doRemove input = withAdminCredentials creds (removeGame gameId)
where
creds = Remove.credentials input
gameId = Remove.gameId input
listGames :: Server [GameId]
listGames = do
state <- S.get
return $ M.keys (games state)