Adds client to client messaging.

This commit is contained in:
Abhinav Sarkar 2015-09-10 00:24:55 +05:30
parent 0cd59a4e92
commit 188d9780e3
2 changed files with 40 additions and 15 deletions

View File

@ -3,6 +3,6 @@ module Link.Protocol where
import Link.Types import Link.Types
parseCommand :: String -> Maybe Message parseCommand :: String -> Maybe Message
parseCommand command = case (words command) of parseCommand command = case words command of
"PRIVMSG" : userName : msg -> Just $ PrivMsg (User userName) (unwords msg) "PRIVMSG" : userName : msg -> Just $ PrivMsg (User userName) (unwords msg)
_ -> Nothing _ -> Nothing

View File

@ -1,8 +1,8 @@
module Link.Server where module Link.Server where
import Control.Exception (finally) import Control.Exception (finally, bracket, throwIO, try, SomeException,
import Control.Concurrent (forkFinally, newMVar, modifyMVar, modifyMVar_, newChan, AsyncException(ThreadKilled))
writeChan, withMVar) import Control.Concurrent
import Control.Monad (forever) import Control.Monad (forever)
import Network (withSocketsDo, listenOn, accept, PortID(..)) import Network (withSocketsDo, listenOn, accept, PortID(..))
import System.IO (hClose, hSetNewlineMode, hSetBuffering, BufferMode(..), import System.IO (hClose, hSetNewlineMode, hSetBuffering, BufferMode(..),
@ -47,11 +47,8 @@ connectClient server handle = do
Just client -> Just client ->
runClient server client `finally` removeClient server user runClient server client `finally` removeClient server user
sendMessage :: Message -> Client -> IO ()
sendMessage message Client {..} = writeChan clientChan message
checkAddClient :: Server -> User -> Handle -> IO (Maybe Client) checkAddClient :: Server -> User -> Handle -> IO (Maybe Client)
checkAddClient Server {..} user@User {..} handle = do checkAddClient Server {..} user@User {..} handle =
modifyMVar serverUsers $ \clientMap -> modifyMVar serverUsers $ \clientMap ->
if Map.member user clientMap if Map.member user clientMap
then return (clientMap, Nothing) then return (clientMap, Nothing)
@ -61,19 +58,47 @@ checkAddClient Server {..} user@User {..} handle = do
printf "New user connected: %s\n" userName printf "New user connected: %s\n" userName
return (Map.insert user client clientMap, Just client) return (Map.insert user client clientMap, Just client)
race :: IO a -> IO b -> IO (Either a b)
race ioa iob = do
m <- newEmptyMVar
bracket (forkFinally (fmap Left ioa) (putMVar m)) cancel $ \_ ->
bracket (forkFinally (fmap Right iob) (putMVar m)) cancel $ \_ -> do
r <- readMVar m
case r of
Left e -> throwIO e
Right a -> return a
where
cancel t = throwTo t ThreadKilled
sendMessage :: Message -> Client -> IO ()
sendMessage message Client {..} = writeChan clientChan message
runClient :: Server -> Client -> IO () runClient :: Server -> Client -> IO ()
runClient Server {..} Client {..} = forever $ do runClient Server {..} Client {..} = forever $ do
command <- hGetLine clientHandle r <- try $ race readCommand readMessage
printf "<%s>: %s\n" (userName clientUser) command case r of
case parseCommand command of Left (e :: SomeException) -> printf "Exception: %s\n" (show e)
Nothing -> return () Right cm -> case cm of
Just com -> handleCommand com Left mcommand -> case mcommand of
Nothing -> printf "Could not parse command\n"
Just command -> handleCommand command
Right message -> handleMessage message
where where
handleCommand message@(PrivMsg user _) = readCommand = do
command <- hGetLine clientHandle
printf "<%s>: %s\n" (userName clientUser) command
return $ parseCommand command
readMessage = readChan clientChan
handleCommand (PrivMsg user msg) =
withMVar serverUsers $ \clientMap -> withMVar serverUsers $ \clientMap ->
case Map.lookup user clientMap of case Map.lookup user clientMap of
Nothing -> printf "No such user: %s\n" (userName user) Nothing -> printf "No such user: %s\n" (userName user)
Just client -> sendMessage message client Just client -> sendMessage (PrivMsg clientUser msg) client
handleMessage (PrivMsg user msg) =
hPrintf clientHandle "PRIVMSG %s %s\n" (userName user) msg
removeClient :: Server -> User -> IO () removeClient :: Server -> User -> IO ()
removeClient Server {..} user = removeClient Server {..} user =