{-# LANGUAGE CPP #-}
module Network.MPD (
MonadMPD, MPD, MPDError(..), ACKType(..), Response,
Host, Port, Password,
withMPD, withMPD_, withMPDEx,
module Network.MPD.Commands,
#ifdef TEST
getConnectionSettings, getEnvDefault
#endif
) where
import Prelude
import qualified Control.Exception as E
import Network.MPD.Commands
import Network.MPD.Core
import System.Environment (getEnv)
import System.IO.Error (isDoesNotExistError)
import Data.Maybe (listToMaybe)
withMPD :: MPD a -> IO (Response a)
withMPD :: forall a. MPD a -> IO (Response a)
withMPD = Maybe String -> Maybe String -> MPD a -> IO (Response a)
forall a. Maybe String -> Maybe String -> MPD a -> IO (Response a)
withMPD_ Maybe String
forall a. Maybe a
Nothing Maybe String
forall a. Maybe a
Nothing
withMPD_ :: Maybe String
-> Maybe String
-> MPD a -> IO (Response a)
withMPD_ :: forall a. Maybe String -> Maybe String -> MPD a -> IO (Response a)
withMPD_ Maybe String
mHost Maybe String
mPort MPD a
action = do
Either String (String, Port, String)
settings <- Maybe String
-> Maybe String -> IO (Either String (String, Port, String))
getConnectionSettings Maybe String
mHost Maybe String
mPort
case Either String (String, Port, String)
settings of
Right (String
host, Port
port, String
pw) -> String -> Port -> String -> MPD a -> IO (Response a)
forall a. String -> Port -> String -> MPD a -> IO (Response a)
withMPDEx String
host Port
port String
pw MPD a
action
Left String
err -> (Response a -> IO (Response a)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Response a -> IO (Response a))
-> (String -> Response a) -> String -> IO (Response a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MPDError -> Response a
forall a b. a -> Either a b
Left (MPDError -> Response a)
-> (String -> MPDError) -> String -> Response a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> MPDError
Custom) String
err
getConnectionSettings :: Maybe String -> Maybe String -> IO (Either String (Host, Port, Password))
getConnectionSettings :: Maybe String
-> Maybe String -> IO (Either String (String, Port, String))
getConnectionSettings Maybe String
mHost Maybe String
mPort = do
(String
host, String
pw) <- String -> (String, String)
parseHost (String -> (String, String)) -> IO String -> IO (String, String)
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap`
IO String -> (String -> IO String) -> Maybe String -> IO String
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (String -> String -> IO String
getEnvDefault String
"MPD_HOST" String
"localhost") String -> IO String
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe String
mHost
String
port <- IO String -> (String -> IO String) -> Maybe String -> IO String
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (String -> String -> IO String
getEnvDefault String
"MPD_PORT" String
"6600") String -> IO String
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe String
mPort
case String -> Maybe Port
forall a. Read a => String -> Maybe a
maybeRead String
port of
Just Port
p -> (Either String (String, Port, String)
-> IO (Either String (String, Port, String))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Either String (String, Port, String)
-> IO (Either String (String, Port, String)))
-> ((String, Port, String) -> Either String (String, Port, String))
-> (String, Port, String)
-> IO (Either String (String, Port, String))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String, Port, String) -> Either String (String, Port, String)
forall a b. b -> Either a b
Right) (String
host, Port
p, String
pw)
Maybe Port
Nothing -> (Either String (String, Port, String)
-> IO (Either String (String, Port, String))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Either String (String, Port, String)
-> IO (Either String (String, Port, String)))
-> (String -> Either String (String, Port, String))
-> String
-> IO (Either String (String, Port, String))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Either String (String, Port, String)
forall a b. a -> Either a b
Left) (String -> String
forall a. Show a => a -> String
show String
port String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" is not a valid port!")
where
parseHost :: String -> (String, String)
parseHost String
s = case Char -> String -> (String, String)
breakChar Char
'@' String
s of
(String
host, String
"") -> (String
host, String
"")
(String
pw, String
host) -> (String
host, String
pw)
getEnvDefault :: String -> String -> IO String
getEnvDefault :: String -> String -> IO String
getEnvDefault String
x String
dflt =
IO String -> (IOError -> IO String) -> IO String
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
E.catch (String -> IO String
getEnv String
x) (\IOError
e -> if IOError -> Bool
isDoesNotExistError IOError
e
then String -> IO String
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return String
dflt else IOError -> IO String
forall a. IOError -> IO a
ioError IOError
e)
breakChar :: Char -> String -> (String, String)
breakChar :: Char -> String -> (String, String)
breakChar Char
c String
s = let (String
x, String
y) = (Char -> Bool) -> String -> (String, String)
forall a. (a -> Bool) -> [a] -> ([a], [a])
break (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
c) String
s in (String
x, Int -> String -> String
forall a. Int -> [a] -> [a]
drop Int
1 String
y)
maybeRead :: Read a => String -> Maybe a
maybeRead :: forall a. Read a => String -> Maybe a
maybeRead = ((a, String) -> a) -> Maybe (a, String) -> Maybe a
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (a, String) -> a
forall a b. (a, b) -> a
fst (Maybe (a, String) -> Maybe a)
-> (String -> Maybe (a, String)) -> String -> Maybe a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [(a, String)] -> Maybe (a, String)
forall a. [a] -> Maybe a
listToMaybe ([(a, String)] -> Maybe (a, String))
-> (String -> [(a, String)]) -> String -> Maybe (a, String)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [(a, String)]
forall a. Read a => ReadS a
reads