module PfeSocket(listenOnPFE,connectToPFE,acceptPFE,removePFE, pfeClient,clientOps,serverOps,sResult,errorString) where import Prelude hiding (putStr,readIO) import Network(listenOn,accept,connectTo,PortID(..)) import IO(hPutStrLn,hPrint,hGetLine,hGetContents,hClose,hSetBuffering,BufferMode(..)) import AbstractIO import MUtils(ifM,done) import SIO listenOnPFE dir = ifM (doesFileExist (pfePath dir)) tryConnect listen where listen = listenOn (pfePort dir) tryConnect = do r <- try connect case r of Left _ -> cleanUp>>listen Right _ -> backoff connect = do h <- connectToPFE dir hPutStrLn h "" s <- hGetContents h seq (length s) done -- to avoid crashing the server hClose h backoff = fail "PFE Server is already running" cleanUp = removePFE dir acceptPFE s = do a@(h,_,_) <- accept s hSetBuffering h IO.LineBuffering return a connectToPFE dir = do h <- connectTo "localhost" (pfePort dir) hSetBuffering h LineBuffering return h pfeClient h args = do inBase $ hPutStrLn h (unwords args) clientLoop inBase $ hClose h where clientLoop = do msg <- inBase $ hReadLn h case msg of Stdout s -> putStr s >> clientLoop Stderr s -> ePutStr s >> clientLoop Result r -> case r of Left s -> fail s Right () -> done removePFE = removeFile . pfePath pfePort = UnixSocket . pfePath pfePath dir = dir++"/pfeserver" data Msg = Stdout String | Stderr String | Result Result deriving (Read,Show) type Result = Either String () serverOps h = StdIO {put=sPut h, eput=sePut h} clientOps = StdIO {put=putStr, eput=ePutStr {-. color-}} -- where color s = "\ESC[31m"++s++"\ESC[m" sPut h = hPrint h . Stdout sePut h = hPrint h . Stderr sResult h = hPrint h . Result . either (Left . show) Right hReadLn h = readIO =<< hGetLine h -- Work around the ugly way GHC prints user errors... errorString e = if isUserError e then dropPrefix "user error\nReason: " (ioeGetErrorString e) else show e dropPrefix (x:xs) (y:ys) | x==y = dropPrefix xs ys dropPrefix _ ys = ys