module Network.MineCraft.Pi.Client.Internal
( MCPI
, runMCPI
, runMCPI'
, query
, command
) where
import qualified Control.Exception as CE
import Control.Exception (bracket)
import Control.Monad (when)
import Control.Monad.IO.Class
import Control.Monad.Trans.Reader
import Data.List (intercalate)
import Network.BSD
import Network.Socket
import System.Exit
import System.IO
type MCPI = ReaderT ConnInfo IO
data ConnInfo = ConnInfo {
_ciHandle :: Handle
, _ciDebug :: Bool
}
type Command = String
type Query = String
type Argument = String
mcPort :: String
mcPort = "4711"
openMCPI ::
Bool
-> IO ConnInfo
openMCPI flag = do
let ehdl :: CE.IOException -> IO ()
ehdl _ = hPutStrLn stderr "ERROR: Unable to connect to MineCraft-PI. Is it running?" >>
exitFailure
as <- getAddrInfo Nothing Nothing (Just mcPort)
let a = head as
sock <- socket (addrFamily a) Stream defaultProtocol
setSocketOption sock KeepAlive 1
connect sock (addrAddress a) `CE.catch` ehdl
h <- socketToHandle sock ReadWriteMode
hSetBuffering h LineBuffering
return $ ConnInfo h flag
closeMCPI :: ConnInfo -> IO ()
closeMCPI = hClose . _ciHandle
logMsg :: ConnInfo -> String -> String -> MCPI ()
logMsg ConnInfo {..} hdr msg =
when _ciDebug $ liftIO $ hPutStrLn stderr $ "*DBG*" ++ hdr ++ "*" ++ msg
addArgs :: String -> [Argument] -> String
addArgs a bs = a ++ "(" ++ intercalate "," bs ++ ")"
command :: Command -> [Argument] -> MCPI ()
command comm args = do
ci <- ask
let commstr = addArgs comm args
logMsg ci "COMMAND" commstr
liftIO $ hPutStrLn (_ciHandle ci) commstr
query :: Query -> [Argument] -> MCPI String
query qry args = do
ci <- ask
let qrystr = addArgs qry args
logMsg ci "QUERY" qrystr
liftIO $ hPutStrLn (_ciHandle ci) qrystr
ans <- liftIO $ hGetLine (_ciHandle ci)
logMsg ci "RESPONSE" ans
return ans
runMCPI' :: Bool -> MCPI a -> IO a
runMCPI' flag p =
bracket
(openMCPI flag)
closeMCPI
(runReaderT p)
runMCPI :: MCPI a -> IO a
runMCPI = runMCPI' False