kevin-0.11.0: src/Kevin/Base.hs
{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveDataTypeable #-}
module Kevin.Base (
module Kevin.Types,
KevinException(..),
_KevinException,
KevinServer(..),
User(..),
module K,
io,
runPrinter,
printf
) where
import Control.Applicative ((<$>))
import Control.Concurrent as K (forkIO)
import Control.Concurrent.Chan as K
import Control.Concurrent.STM.TVar as K
import Control.Exception
import Control.Exception as K (IOException)
import Control.Exception.Lens
import Control.Lens as K
#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 707
import Control.Monad.Catch as K
#else
import Control.Monad.CatchIO as K
#endif
import Control.Monad.Reader as K
import qualified Data.ByteString.Char8 as T (hGetLine, hPutStr)
import qualified Data.Text as T
import qualified Data.Text.Encoding as T
import Data.Typeable
import Kevin.Chatrooms as K
import Kevin.Settings as K
import Kevin.Types
import Kevin.Util.Logger
import Network as K
import System.IO as K
import System.IO.Error
import qualified Text.Printf as P
runPrinter :: Chan T.Text -> Handle -> IO ()
runPrinter ch h = void . forkIO . forever $ readChan ch >>= T.hPutStr h . T.encodeUtf8
io :: MonadIO m => IO a -> m a
io = liftIO
class KevinServer a where
readClient, readServer :: a -> IO T.Text
writeClient, writeServer :: a -> T.Text -> IO ()
closeClient, closeServer :: a -> IO ()
data KevinException = ServerParseFailure String T.Text
| ClientParseFailure String T.Text
| ServerClosed
| ClientClosed
deriving Typeable
instance Show KevinException where
show (ServerParseFailure reason input) =
P.printf "Parse failure (%s) on packet from server:\n%s" reason (show input)
show (ClientParseFailure reason input) =
P.printf "Parse failure (%s) on packet from client:\n%s" reason (show input)
show ServerClosed = "Server closed connection"
show ClientClosed = "Client closed connection"
instance Exception KevinException
_KevinException :: Prism' SomeException KevinException
_KevinException = exception
-- actions
hGetCharTimeout :: Handle -> Int -> IO Char
hGetCharTimeout h t = do
hSetBuffering h NoBuffering
ready <- hWaitForInput h t
if ready
then hGetChar h
else throwIO $ mkIOError eofErrorType "read timeout" (Just h) Nothing
hGetSep :: Char -> Handle -> IO String
hGetSep sep h = fix $ \f -> do
ch <- hGetCharTimeout h 180000
if ch == sep
then return ""
else (ch:) <$> f
instance KevinServer Kevin where
readClient k = do
line <- T.decodeUtf8 <$> T.hGetLine (irc k)
return $ T.init line
readServer k = T.pack <$> hGetSep '\NUL' (damn k)
writeClient k = writeChan (iChan k)
writeServer k = writeChan (dChan k)
closeClient = hClose . irc
closeServer = hClose . damn