packages feed

kevin-0.11.0: src/Kevin/Protocol.hs

{-# LANGUAGE FlexibleContexts #-}

module Kevin.Protocol (kevinServer) where

import           Control.Concurrent
import           Control.Exception        (throwIO)
import           Control.Exception.Lens
import           Control.Monad.State
import           Data.Default
import           Data.Monoid              (mempty)
import           Kevin.Base
import qualified Kevin.Damn.Protocol as S
import qualified Kevin.IRC.Protocol as C
import           Kevin.Util.Logger
import           Prelude

watchInterrupt :: [Handler IO (Maybe Kevin)]
watchInterrupt = [ handler _AsyncException throwIO
                 , handler_ id (return Nothing) ]

mkKevin :: Socket -> IO (Maybe Kevin)
mkKevin sock = flip catches watchInterrupt . withSocketsDo
    $ do (client, _, _) <- accept sock
         hSetBuffering client NoBuffering
         klogNow Blue "received a client"
         s <- execStateT (C.getAuthInfo client False) def
         damnSock <- connectTo "chat.deviantart.com" $ PortNumber 3900
         hSetBuffering damnSock NoBuffering
         logChan <- newChan
         damnChan <- newChan
         ircChan <- newChan
         smv <- newEmptyMVar
         cmv <- newEmptyMVar
         return . Just $ Kevin damnSock
                               client
                               damnChan
                               ircChan
                               smv
                               cmv
                               s
                               mempty
                               mempty
                               mempty
                               mempty
                               False
                               logChan

mkListener :: Int -> IO Socket
mkListener = listenOn . PortNumber . fromIntegral

kevinServer :: Int -> IO ()
kevinServer n = do
    sock <- mkListener n
    putStrLn $ "Listening on port " ++ show n
    forever $ do
        kev <- mkKevin sock
        case kev of Just k -> listen k
                    Nothing -> return ()

listen :: Kevin -> IO ()
listen k = do
    mvar <- newTVarIO k
    runLogger (logger k)
    runPrinter (dChan k) (damn k)
    runPrinter (iChan k) (irc k)
    sId <- forkIO . void $ runReaderT (bracket_ S.initialize (S.cleanup >> io (closeServer k)) S.listen) mvar
    cId <- forkIO . void $ runReaderT (bracket_ (return ()) (C.cleanup >> io (closeClient k)) C.listen) mvar
    putMVar (serverMv k) sId
    putMVar (clientMv k) cId
    return ()