module Database.PlistBuddy.Command
( command
, recvReply0
, myWritePty
)
where
import Control.Exception
import Control.Monad
import Data.Word (Word8)
import Data.Char (ord)
import Database.PlistBuddy.Types
import qualified Data.ByteString as BS
import Data.ByteString (ByteString)
import Data.Monoid ((<>))
import System.Posix.Pty
import System.Timeout
command :: Plist -> ByteString -> IO ByteString
command plist input = todo
where
d = plist_debug plist
pty = plist_pty plist
write txt = do
when d $ print ("write"::String,txt)
myWritePty pty txt
todo = do
write (input <> "\n")
r <- recvReply pty
when d $ print ("read"::String,r)
return $ r
recvReply0 :: Pty -> IO ByteString
recvReply0 pty = readMe []
where
readMe rbs = do
v <- myReadPty pty
testMe ( BS.filter (`notElem` toIgnore) v : rbs)
toIgnore :: [Word8]
toIgnore = BS.unpack "\r\n#"
testMe rbs | "Command: Unrecognized CommandCommand: " `isSuffixOf` rbs
= return $ ""
| otherwise
= readMe rbs
where
bs = rbsToByteString rbs
recvReply :: Pty -> IO ByteString
recvReply pty = readMe []
where
prompt = "\nCommand: "
readMe rbs = do
v <- myReadPty pty
testMe ( BS.filter (/= fromIntegral (ord '\r')) v : rbs)
testMe rbs | prompt `isSuffixOf` rbs
= return $ BS.take (BS.length bs BS.length prompt) bs
| "Command: " == bs
= return $ ""
| otherwise
= readMe rbs
where
bs = rbsToByteString rbs
type RBS = [ByteString]
rbsToByteString :: RBS -> ByteString
rbsToByteString = BS.concat . reverse
isSuffixOf :: ByteString -> RBS -> Bool
isSuffixOf bs rbs = bs `BS.isSuffixOf` rbsToByteString rbs
myWritePty :: Pty -> ByteString -> IO ()
myWritePty pty msg = do
r <- myTimeout $ do
threadWaitWritePty pty
writePty pty msg
case r of
Just () -> return ()
Nothing -> do
throw $ PlistBuddyException "timeout when writing"
myReadPty :: Pty -> IO ByteString
myReadPty pty = do
r <- myTimeout $ do
threadWaitReadPty pty
tryReadPty pty
case r of
Just (Left {}) -> myReadPty pty
Just (Right v) -> return v
Nothing -> do
throw $ PlistBuddyException "timeout when reading"
myTimeout :: IO a -> IO (Maybe a)
myTimeout = timeout (1000 * 1000)