2018-04-11 13:25:24 +02:00
|
|
|
{-# LANGUAGE NamedFieldPuns #-}
|
|
|
|
{-# LANGUAGE FlexibleInstances #-}
|
2018-05-11 12:31:53 +02:00
|
|
|
{-# LANGUAGE FlexibleContexts #-}
|
2018-04-11 13:25:24 +02:00
|
|
|
{-# LANGUAGE MultiParamTypeClasses #-}
|
2018-05-11 12:31:53 +02:00
|
|
|
{-# LANGUAGE OverloadedStrings #-}
|
|
|
|
{-# LANGUAGE ScopedTypeVariables #-}
|
2018-05-13 18:08:12 +02:00
|
|
|
{-# LANGUAGE AllowAmbiguousTypes #-}
|
2018-04-11 13:25:24 +02:00
|
|
|
module Server (
|
2018-04-12 23:01:40 +02:00
|
|
|
T(..)
|
2018-04-11 13:25:24 +02:00
|
|
|
, disconnect
|
2018-05-11 12:31:53 +02:00
|
|
|
, get
|
2018-04-11 13:25:24 +02:00
|
|
|
, logIn
|
|
|
|
, logOut
|
|
|
|
, new
|
2018-05-11 12:31:53 +02:00
|
|
|
, register
|
2018-05-13 18:08:12 +02:00
|
|
|
, update
|
2018-04-11 13:25:24 +02:00
|
|
|
) where
|
|
|
|
|
2018-05-11 12:31:53 +02:00
|
|
|
import Data.Aeson (ToJSON(..), (.=), object, pairs)
|
|
|
|
import Data.Map (Map, (!), (!?), adjust, delete, insert, lookupMax, mapWithKey)
|
2018-04-12 23:01:40 +02:00
|
|
|
import qualified Data.Map as Map (empty)
|
2018-05-11 12:31:53 +02:00
|
|
|
import Data.Monoid ((<>))
|
|
|
|
import Data.Set (Set, member)
|
|
|
|
import qualified Data.Set as Set (delete, empty, insert)
|
|
|
|
import Data.Text (Text)
|
2018-04-11 13:25:24 +02:00
|
|
|
import qualified Data (RW(..))
|
2018-07-12 22:33:13 +02:00
|
|
|
import qualified Game (Key, T)
|
2018-05-11 12:31:53 +02:00
|
|
|
import qualified Player (Key, T(..))
|
2018-05-13 18:08:12 +02:00
|
|
|
import qualified Session (Status(..), T(..), Update)
|
2018-04-11 13:25:24 +02:00
|
|
|
|
2018-05-11 12:31:53 +02:00
|
|
|
type Names = Set Text
|
|
|
|
type Players = Map Player.Key Player.T
|
|
|
|
type Sessions = Map Player.Key Session.T
|
|
|
|
type Games = Map Game.Key Game.T
|
2018-04-11 13:25:24 +02:00
|
|
|
data T = T {
|
2018-05-11 12:31:53 +02:00
|
|
|
names :: Names
|
|
|
|
, players :: Players
|
2018-04-12 23:01:40 +02:00
|
|
|
, sessions :: Sessions
|
2018-05-11 12:31:53 +02:00
|
|
|
, games :: Games
|
2018-04-11 13:25:24 +02:00
|
|
|
}
|
|
|
|
|
2018-04-12 23:01:40 +02:00
|
|
|
instance Data.RW Names T where
|
2018-05-11 12:31:53 +02:00
|
|
|
get = names
|
|
|
|
set names server = server {names}
|
|
|
|
|
|
|
|
instance Data.RW Players T where
|
|
|
|
get = players
|
|
|
|
set players server = server {players}
|
2018-04-11 13:25:24 +02:00
|
|
|
|
2018-04-12 23:01:40 +02:00
|
|
|
instance Data.RW Sessions T where
|
2018-05-11 12:31:53 +02:00
|
|
|
get = sessions
|
|
|
|
set sessions server = server {sessions}
|
|
|
|
|
|
|
|
instance Data.RW Games T where
|
|
|
|
get = games
|
|
|
|
set games server = server {games}
|
|
|
|
|
|
|
|
newtype Player = Player (Text, Bool)
|
|
|
|
instance ToJSON Player where
|
|
|
|
toJSON (Player (name, alone)) = object ["name" .= name, "alone" .= alone]
|
|
|
|
toEncoding (Player (name, alone)) = pairs ("name" .= name <> "alone" .= alone)
|
|
|
|
|
|
|
|
export :: Sessions -> Player.Key -> Player.T -> Player
|
|
|
|
export sessions key player = Player (Player.name player, alone)
|
|
|
|
where
|
|
|
|
alone =
|
|
|
|
case Session.status (sessions ! key) of
|
|
|
|
Session.LoggedIn True -> True
|
|
|
|
_ -> False
|
2018-04-11 13:25:24 +02:00
|
|
|
|
|
|
|
instance ToJSON T where
|
2018-05-11 12:31:53 +02:00
|
|
|
toJSON (T {players, sessions}) = toJSON $ mapWithKey (export sessions) players
|
|
|
|
toEncoding (T {players, sessions}) = toEncoding $ mapWithKey (export sessions) players
|
2018-04-11 13:25:24 +02:00
|
|
|
|
|
|
|
new :: T
|
|
|
|
new = T {
|
2018-05-11 12:31:53 +02:00
|
|
|
names = Set.empty
|
|
|
|
, players = Map.empty
|
2018-04-12 23:01:40 +02:00
|
|
|
, sessions = Map.empty
|
2018-05-11 12:31:53 +02:00
|
|
|
, games = Map.empty
|
2018-04-11 13:25:24 +02:00
|
|
|
}
|
|
|
|
|
2018-05-11 12:31:53 +02:00
|
|
|
register :: forall a b. (Enum a, Ord a, Data.RW (Map a b) T) => b -> T -> (T, a)
|
|
|
|
register x server =
|
|
|
|
let key = maybe (toEnum 0) (\(n, _) -> succ n) $ lookupMax $ (Data.get server :: Map a b) in
|
|
|
|
(Data.update (insert key x) server, key)
|
|
|
|
|
|
|
|
get :: forall a b. (Ord a, Data.RW (Map a b) T) => a -> T -> b
|
|
|
|
get key server = (Data.get server :: Map a b) ! key
|
2018-04-11 13:25:24 +02:00
|
|
|
|
2018-05-13 18:08:12 +02:00
|
|
|
update :: forall a b. (Ord a, Data.RW (Map a b) T) => a -> (b -> b) -> T -> T
|
|
|
|
update key updator =
|
|
|
|
Data.update (adjust updator key :: Map a b -> Map a b)
|
|
|
|
|
2018-04-12 23:01:40 +02:00
|
|
|
disconnect :: Player.Key -> T -> T
|
|
|
|
disconnect key =
|
|
|
|
Data.update (delete key :: Sessions -> Sessions) . logOut key
|
2018-04-11 13:25:24 +02:00
|
|
|
|
2018-05-11 12:31:53 +02:00
|
|
|
logIn :: Text -> Player.Key -> T -> Either String T
|
2018-04-12 23:01:40 +02:00
|
|
|
logIn name key server =
|
2018-05-11 12:31:53 +02:00
|
|
|
Data.update (Set.insert name) .
|
|
|
|
Data.update (insert key $ Player.T {Player.name}) .
|
2018-05-13 18:08:12 +02:00
|
|
|
update key (Data.set $ Session.LoggedIn True :: Session.Update) <$>
|
2018-05-11 12:31:53 +02:00
|
|
|
if name `member` names server
|
|
|
|
then Left "This name is already registered"
|
|
|
|
else Right server
|
2018-04-12 23:01:40 +02:00
|
|
|
|
|
|
|
logOut :: Player.Key -> T -> T
|
|
|
|
logOut key server =
|
|
|
|
maybe
|
|
|
|
server
|
2018-05-11 12:31:53 +02:00
|
|
|
(\player ->
|
|
|
|
Data.update (delete key :: Players -> Players) $
|
2018-05-13 18:08:12 +02:00
|
|
|
update key (Data.set $ Session.LoggedIn False :: Session.Update) $
|
2018-05-11 12:31:53 +02:00
|
|
|
Data.update (Set.delete $ Player.name player :: Names -> Names) server)
|
|
|
|
(players server !? key)
|