Holumbus-Distribution-0.1.0: Examples/Distribution/ChatDChan/ServerDChan.hs
-- ----------------------------------------------------------------------------
{- |
Module : Holumbus
Copyright : Copyright (C) 2009 Stefan Schmidt
License : MIT
Maintainer : Stefan Schmidt (stefanschmidt@web.de)
Stability : experimental
Portability: portable
Version : 0.1
-}
-- ----------------------------------------------------------------------------
module Main(main) where
import Control.Concurrent
import qualified Data.Map as Map
import Data.Maybe
import qualified Data.Set as Set
import Holumbus.Distribution.DNode
import Holumbus.Distribution.DChan
import Holumbus.Common.Logging
import MessagesDChan
data ServerData = ServerData {
sd_clients :: Map.Map ClientToken (String, (DChan ChatResponse))
, sd_names :: Set.Set String
, sd_number :: Integer
}
main :: IO ()
main
= do
initializeLogging []
initDNode $ (defaultDNodeConfig "ServerDChan")
{ dnc_MinPort = (fromInteger 7999), dnc_MaxPort = (fromInteger 7999) }
let serverdata = mkNewServer
channel <- newDChan "server"
forkIO $ dispatcher serverdata channel
repeatTillReturn
closeDChan channel
deinitDNode
mkNewServer :: ServerData
mkNewServer = ServerData Map.empty Set.empty 1
mkNextClientToken :: ServerData -> IO (ServerData, ClientToken)
mkNextClientToken s
= do
let i = sd_number s
s' = s { sd_number = (i+1)}
t <- genClientToken i
return (s', t)
addClient :: ServerData -> ClientToken -> String -> DChan ChatResponse -> ServerData
addClient s ct cn cc = s { sd_clients = c' , sd_names = n' }
where
c' = Map.insert ct (cn,cc) (sd_clients s)
n' = Set.insert cn (sd_names s)
deleteClient :: ServerData -> ClientToken -> ServerData
deleteClient s ct = s { sd_clients = c' , sd_names = n' }
where
c' = Map.delete ct (sd_clients s)
n' = case (Map.lookup ct (sd_clients s)) of
(Just (cn,_)) -> Set.delete cn (sd_names s)
(Nothing) -> (sd_names s)
isTokenValid :: ServerData -> ClientToken -> Bool
isTokenValid s ct = Map.member ct (sd_clients s)
isNameValid :: ServerData -> String -> Bool
isNameValid _ "" = False
isNameValid s cn = (not $ Set.member cn (sd_names s))
sendMessage :: ServerData -> ClientToken -> String -> IO ()
sendMessage s ct text
= do
if (isTokenValid s ct)
then do
let (cn, _) = fromJust $ Map.lookup ct (sd_clients s)
ccs = map (snd) $ Map.elems $ Map.delete ct (sd_clients s)
mapM (\cc -> writeDChan cc (RspMessage cn text)) ccs
return ()
else return ()
repeatTillReturn :: IO ()
repeatTillReturn
= do
hnd <- getDNodeData
putStrLn $ show hnd
l <- getLine
case l of
"exit" ->
return ()
"debug" ->
do
nd <- getDNodeData
putStrLn $ show nd
_ ->
repeatTillReturn
dispatcher :: ServerData -> DChan ChatRequest -> IO ()
dispatcher s c
= do
msg <- readDChan c
s' <- case msg of
(ReqRegister cn cc) ->
do
if (isNameValid s cn)
then do
(s', ct) <- mkNextClientToken s
writeDChan cc (RspRegister ct)
return $ addClient s' ct cn cc
else do
writeDChan cc (RspError "name already used")
return s
(ReqUnregister ct) ->
do
return $ deleteClient s ct
(ReqMessage ct text) ->
do
sendMessage s ct text
return s
dispatcher s' c