packages feed

hexpat-iteratee-0.4: test/client-server/server.hs

{-# LANGUAGE OverloadedStrings #-}
import Control.Concurrent
import Control.Exception
import Control.Monad
import Control.Monad.IO.Class
import Control.Monad.ListT
import qualified Data.ByteString as B
import qualified Data.ByteString.Unsafe as B (unsafeUseAsCStringLen)
import Data.Iteratee
import Data.Iteratee.IO.Fd
import Data.Iteratee.WrappedByteString
import Data.List.Class
import Data.Text (Text)
import qualified Data.Text as T
import Network
import System.IO
import System.Posix.IO (handleToFd, fdWriteBuf, closeFd)
import System.Posix.Types (Fd)
import Text.XML.Expat.Chunked
import Text.XML.Expat.Format
import Foreign.Ptr


main :: IO ()
main = do
    let port = 6333
    putStrLn $ "listening on port "++show port
    ls <- listenOn $ PortNumber port
    forever $ do
        (h, _, _) <- accept ls
        forkIO $ handleToFd h >>= \fd -> do
            iter <- parse defaultParserOptions (session fd)
            result <- enumFd fd iter >>= run
            print result
          `finally`
            closeFd fd

fdPutStrBS :: Fd -> B.ByteString -> IO ()
fdPutStrBS fd bs = B.unsafeUseAsCStringLen bs $ \(buf, len) ->
        writeFully (castPtr buf) (fromIntegral len)
  where
    writeFully _ len | len == 0 = return ()
    writeFully buf len = do
        written <- fdWriteBuf fd buf len
        if written < 0
            then fail "write failed"
            else writeFully (buf `plusPtr` fromIntegral written) (len - written)

session :: Fd                      -- ^ Socket for writing output to
        -> ListOf (UNode IO Text)  -- ^ Input XML document
        -> XMLT IO ()
session fd inputXML = do
    let outputXML = formatG $ indent 2 $ Element "server" [] (processRoot inputXML)
    execute $ liftIO . fdPutStrBS fd =<< outputXML
    return ()

processRoot :: ListOf (UNode IO Text) -> ListOf (UNode IO Text)
processRoot root = do
    Element _ _ children <- root
    child <- children
    extractElements child
  where
    extractElements :: UNode IO Text -> UNodes IO Text
    extractElements elt | isElement elt = processCommand elt `cons` mzero
    extractElements _                   = mzero

processCommand :: UNode IO Text -> UNode IO Text
processCommand (Element "hello" _ _) = Element "hello-back" [] mzero
processCommand (Element cmd _ _) = Element "unknown" [("command", cmd)] mzero