1 {-# LANGUAGE ViewPatterns #-}
2 module Cryptsy
.API
.Public
.Internal
where
5 import Network
.Browser
(request
)
6 import Network
.HTTP
.Base
(defaultGETRequest_
, rspBody
, rspCode
)
9 import Data
.Aeson
(Value
(Object
), eitherDecode
, withObject
)
10 import Data
.Aeson
.Types
(Parser
, parseEither
)
13 import Control
.Monad
.Trans
.Either (hoistEither
, left
, right
)
14 import Data
.Either.Combinators
(mapLeft
)
17 import Control
.Error
.Util
((??
))
20 import Network
.URI
(parseAbsoluteURI
)
23 import Data
.Text
(Text
, pack
)
26 import Control
.Monad
.Trans
.Class
(lift
)
28 -- unordered-containers
29 import qualified Data
.HashMap
.Strict
as HM
(lookup)
32 import Cryptsy
.API
.Public
.Types
.Error
33 import Cryptsy
.API
.Public
.Types
.Monad
35 -- |generates public API URL
36 pubURL
:: String -- ^ method value
37 -> String -- ^ complete URL
38 pubURL
= ("http://pubapi.cryptsy.com/api.php?method=" ++)
39 {-# INLINABLE pubURL #-}
44 {-# INLINABLE dataStr #-}
46 -- |key in JSON object for return data
48 dataKey
= pack dataStr
49 {-# INLINABLE dataKey #-}
51 -- |key in JSON object for error message
53 errMsgKey
= pack
"error"
55 -- |common request implementation
56 pubCryptsy
:: String -- ^ URL
57 -> (Value
-> Parser a
)
59 pubCryptsy apiurl parser
= do
60 uri
<- parseAbsoluteURI apiurl ?? BadURL apiurl
61 let req
= defaultGETRequest_ uri
62 (_
, resp
) <- lift
$ request req
63 bodyBytes
<- case rspCode resp
of
64 (2, 0, 0) -> right
$ rspBody resp
65 _
-> left
$ BadResponse resp
66 valueJSON
<- hoistEither
. mapLeft
(FailParseResponse bodyBytes
)
67 $ eitherDecode bodyBytes
68 returnData
<- case valueJSON
of
69 Object
(HM
.lookup dataKey
-> Just dat
) -> right dat
70 Object
(HM
.lookup errMsgKey
-> Just errMsg
) ->
71 left
$ ErrorResponse errMsg
72 _
-> left
$ UnsuccessfulResponse valueJSON
73 hoistEither
. mapLeft
(FailParseReturn returnData
)
74 $ parseEither parser returnData
75 {-# INLINABLE pubCryptsy #-}
77 -- |unpacked 'marketsKey'
79 marketsStr
= "markets"
80 {-# INLINABLE marketsStr #-}
82 -- |failure message when 'marketsKey' is missing
84 missingMsg
= "Missing '" ++ marketsStr
++ "' key."
85 {-# INLINABLE missingMsg #-}
87 -- |key in JSON object for market data
89 marketsKey
= pack marketsStr
90 {-# INLINABLE marketsKey #-}
92 -- |Apply a parser on the 'marketsKey' of an object. If not an object or the
93 -- key is missing, fail.
94 onMarkets
:: (Value
-> Parser a
) -> Value
-> Parser a
95 onMarkets parser
= withObject marketsStr
$
96 maybe (fail missingMsg
) parser
. HM
.lookup marketsKey
97 {-# INLINABLE onMarkets #-}