module Cryptsy.API.Public.Internal where
import Control.Exception (try)
import Data.Functor ((<$))
import Data.Aeson (Value(Object), withObject, json')
import Data.Aeson.Types (Parser, parseEither)
import Control.Monad.Trans.Either (EitherT(..), hoistEither)
import Data.Either.Combinators (mapLeft)
import Network.HTTP.Client
( cookieJar, parseUrl, responseBody, responseCookieJar
)
import Pipes.Attoparsec (parse)
import Pipes.HTTP (withHTTP)
import Data.Text (Text, pack)
import Control.Monad.Trans.Reader (ReaderT(..))
import Control.Monad.Trans.State (StateT(..))
import Control.Monad.Trans.State.Strict (evalStateT)
import qualified Data.HashMap.Strict as HM (lookup)
import Cryptsy.API.Public.Types.Error
import Cryptsy.API.Public.Types.Monad
pubURL :: String
-> String
pubURL = ("http://pubapi.cryptsy.com/api.php?method=" ++)
dataStr :: String
dataStr = "return"
dataKey :: Text
dataKey = pack dataStr
errMsgKey :: Text
errMsgKey = pack "error"
pubCryptsy :: String
-> (Value -> Parser a)
-> PubCryptsy a
pubCryptsy apiurl parser = ReaderT $ \manager -> do
reqSansCookies <- hoistEither . mapLeft (BadURL apiurl) $ parseUrl apiurl
parseResult <- EitherT . StateT $ \beforeCookies -> do
let req = reqSansCookies { cookieJar = beforeCookies }
thttp <- try . withHTTP req manager $ \resp -> do
tpr <- try . evalStateT (parse json') $ responseBody resp
return (tpr, responseCookieJar resp <$ beforeCookies)
return $ case thttp of
Left he -> (Left $ FailReadResponse req he, beforeCookies)
Right (Left he, nc) -> (Left $ FailReadResponse req he, nc)
Right (Right pr, nc) -> (Right pr, nc)
hoistEither $ do
value <- mapLeft FailParseResponse parseResult
dat <- case value of
Object (HM.lookup dataKey -> Just d) -> Right d
Object (HM.lookup errMsgKey -> Just errMsg) ->
Left $ ErrorResponse errMsg
_ -> Left $ UnsuccessfulResponse value
mapLeft (FailParseReturn dat) $ parseEither parser dat
marketsStr :: String
marketsStr = "markets"
missingMsg :: String
missingMsg = "Missing '" ++ marketsStr ++ "' key."
marketsKey :: Text
marketsKey = pack marketsStr
onMarkets :: (Value -> Parser a) -> Value -> Parser a
onMarkets parser = withObject marketsStr $
maybe (fail missingMsg) parser . HM.lookup marketsKey