module GHC.Server.Client where
import GHC.Server.Import
import GHC.Server.Sexp
import Control.Monad.Fix
import qualified Data.AttoLisp as L
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as L
import System.IO
startClient :: Show a => Handle -> String -> a -> Server -> IO b
startClient handle host remotePort server@Server{..} =
do logger (Notice ("Client connected from " ++ host ++ " on port " ++ show remotePort))
hSetBuffering handle LineBuffering
forever
(do line <- B.hGetLine handle
case fromLispString line of
Left err ->
do hostLogger Error (show line)
hostLogger Error err
let reply = BadInput err
hostLogger Debug ("<- " ++ show reply)
hPutLn handle (L.encode reply)
Right (Request id cmd) ->
void (forkIO (handleRequest handle id cmd server hostLogger)))
where hostLogger typ text = logger (typ (host ++ ":" ++ show remotePort ++ ": " ++ text))
handleRequest :: Handle -> Integer -> Cmd -> Server
-> ((String -> Log) -> [Char] -> IO a) -> IO ()
handleRequest handle id cmd Server{..} hostLogger =
do hostLogger Debug (show id ++ " -> " ++ show cmd)
out <- newChan
writeChan serverIn (cmd,out)
fix (\loop ->
do response <- readChan out
case response of
Result r -> do reply False response
loop
EndResult r -> reply True response
ErrorResult e -> reply True response)
where reply done x = do let direction = if done then " <- " else " .. "
hostLogger Debug (show id ++ direction ++ show x)
hPutLn handle (L.encode (Response id x))
hPutLn :: Handle -> L.ByteString -> IO ()
hPutLn h ps = L.hPut h ps >> L.hPut h (L.singleton 0x0a)