server/src/Message.hs

88 lines
2.4 KiB
Haskell

{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE DeriveGeneric #-}
module Message (
FromClient(..)
, T(..)
, broadcast
, get
, receive
, relay
, send
, sendTo
) where
import Data.Map (toList)
import Data.Aeson (FromJSON(..), ToJSON(..), eitherDecode', encode, genericParseJSON, genericToEncoding, defaultOptions)
import Network.WebSockets (receiveData, sendTextData)
import Data.ByteString.Lazy.Char8 (unpack)
import Control.Monad (mapM_)
import Control.Monad.Reader (asks, lift)
import qualified Player (Key, Name, Session(..))
import qualified Server (T(..))
import qualified Session (App, T(..), connection, current, debug, server)
import qualified Hanafuda.KoiKoi as KoiKoi (Move(..))
import GHC.Generics (Generic)
import Game ()
data FromClient =
Answer {accept :: Bool}
| Invitation {to :: Player.Key}
| LogIn {name :: Player.Name}
| LogOut
| Game {move :: KoiKoi.Move}
| 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}
| Pong
| Error {error :: String}
deriving (Generic)
instance ToJSON T where
toEncoding = genericToEncoding defaultOptions
sendTo :: (Player.Key, Player.Session) -> T -> Session.App ()
sendTo (key, session) obj = do
Session.debug $ '(' : show key ++ ") <" ++ (unpack encoded)
lift $ sendTextData (Player.connection session) $ encoded
where
encoded = encode $ obj
send :: T -> Session.App ()
send obj = do
key <- asks Session.key
session <- Session.current
sendTo (key, session) obj
broadcast :: T -> Session.App ()
broadcast obj =
(toList . Server.sessions) <$> Session.server
>>= mapM_ (flip sendTo obj)
relay :: FromClient -> (T -> Session.App ()) -> Session.App ()
relay message f = do
Session.debug "Relaying"
(\from -> f $ Relay {from, message}) =<< asks Session.key
receive :: Session.App FromClient
receive = do
received <- ((lift . receiveData) =<< Session.connection)
Session.debug $ '>':(unpack received)
case eitherDecode' received of
Left errorMessage -> send (Message.Error errorMessage) >> receive
Right clientMessage -> return clientMessage
get :: Session.App Message.FromClient
get =
receive >>= pong
where
pong Ping = send Pong >> get
pong m = return m