server/src/Message.hs

106 lines
3.0 KiB
Haskell
Raw Normal View History

2018-04-11 13:25:24 +02:00
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleContexts #-}
2018-04-11 13:25:24 +02:00
module Message (
FromClient(..)
, T(..)
, broadcast
, get
, notifyPlayers
2018-04-11 13:25:24 +02:00
, receive
, relay
, send
, sendTo
, update
2018-04-11 13:25:24 +02:00
) where
import Data.List (intercalate)
import Data.Foldable (forM_)
import Data.Map (keys)
import Data.Aeson (FromJSON(..), ToJSON(..), Value, eitherDecode', encode, genericParseJSON, genericToEncoding, defaultOptions)
2018-04-11 13:25:24 +02:00
import Network.WebSockets (receiveData, sendTextData)
import Data.ByteString.Lazy.Char8 (unpack)
import Data.Text (Text)
import Control.Monad.Reader (asks, lift)
import qualified Player (Key)
import qualified Game (T, export)
import qualified Session (T(..))
import qualified Server (T(..), get)
import qualified App (Context(..), T, connection, debug, server)
2019-08-12 23:01:08 +02:00
import qualified Hanafuda.KoiKoi as KoiKoi (Action, Game(..), Move(..))
2018-04-11 13:25:24 +02:00
import GHC.Generics (Generic)
data FromClient =
Answer {accept :: Bool}
| Invitation {to :: Player.Key}
| LogIn {name :: Text}
2018-04-11 13:25:24 +02:00
| LogOut
| Play {move :: KoiKoi.Move}
2019-08-12 23:01:08 +02:00
| Quit
2018-04-11 13:25:24 +02:00
| Ping
deriving (Generic)
instance ToJSON FromClient where
toEncoding = genericToEncoding defaultOptions
instance FromJSON FromClient where
parseJSON = genericParseJSON defaultOptions
data T =
Relay {from :: Player.Key, message :: FromClient}
| Welcome {room :: Server.T, key :: Player.Key}
| Update {alone :: [Player.Key], paired :: [Player.Key]}
| Game {game :: Value, logs :: [KoiKoi.Action]}
2018-04-11 13:25:24 +02:00
| Pong
| Error {error :: String}
deriving (Generic)
instance ToJSON T where
toEncoding = genericToEncoding defaultOptions
sendTo :: [Player.Key] -> T -> App.T ()
sendTo playerKeys obj = do
sessions <- getSessions <$> App.server
App.debug $ '(' : intercalate ", " recipients ++ ") <" ++ (unpack encoded)
lift $ forM_ (Session.connection <$> sessions) $ flip sendTextData encoded
2018-04-11 13:25:24 +02:00
where
encoded = encode $ obj
getSessions server = (\key -> Server.get key server) <$> playerKeys
recipients = show <$> playerKeys
2018-04-11 13:25:24 +02:00
send :: T -> App.T ()
send obj = do
key <- asks App.key
sendTo [key] obj
2018-04-11 13:25:24 +02:00
broadcast :: T -> App.T ()
2018-04-11 13:25:24 +02:00
broadcast obj =
App.server >>= flip sendTo obj . keys . Server.sessions
2018-04-11 13:25:24 +02:00
relay :: FromClient -> (T -> App.T ()) -> App.T ()
relay message f = do
App.debug "Relaying"
(\from -> f $ Relay {from, message}) =<< asks App.key
2018-04-11 13:25:24 +02:00
receive :: App.T FromClient
2018-04-11 13:25:24 +02:00
receive = do
received <- ((lift . receiveData) =<< App.connection)
App.debug $ '>':(unpack received)
2018-04-11 13:25:24 +02:00
case eitherDecode' received of
Left errorMessage -> send (Message.Error errorMessage) >> receive
Right clientMessage -> return clientMessage
get :: App.T Message.FromClient
get =
receive >>= pong
where
pong Ping = send Pong >> get
pong m = return m
update :: T
update = Update {alone = [], paired = []}
notifyPlayers :: Game.T -> [KoiKoi.Action] -> App.T ()
notifyPlayers game logs =
2018-07-15 17:57:40 +02:00
forM_ (keys $ KoiKoi.scores game) $ \k ->
sendTo [k] $ Game {game = Game.export k game, logs}