liblastfm-0.0.3.2: src/Network/Lastfm/Internal.hs
{-# LANGUAGE ScopedTypeVariables #-}
-- | Response module
{-# OPTIONS_HADDOCK hide #-}
module Network.Lastfm.Internal
( ResponseType(..)
, callAPI, callAPIsigned, xml, json, (#)
, module Network.Lastfm
) where
import Control.Applicative ((<$>))
import Control.Arrow ((&&&), second)
import Data.Function (on)
import Data.List (sortBy)
import Codec.Binary.UTF8.String (encodeString)
import Data.ByteString.Lazy.Char8 (ByteString)
import qualified Data.ByteString.Lazy.Char8 as BS
import Data.Digest.Pure.MD5 (md5)
import Data.URLEncoded (urlEncode, export)
import Network.Curl
import Network.Lastfm
import Network.Lastfm.Error
import Network.Lastfm.TH
-- Send POST query to Lastfm API
callAPI ∷ ResponseType → [(String, String)] → Lastfm Response
callAPI t = query (parseError t) . insertType t . map (second encodeString)
-- Send signed POST query to Lastfm API
callAPIsigned ∷ ResponseType → Secret → [(String, String)] → Lastfm Response
callAPIsigned t (Secret s) xs = query (parseError t) zs
where
ys = map (second encodeString) . filter (not . null . snd) $ xs
zs = insertType t $ ("api_sig", sign ys) : ys
sign ∷ [(String, String)] → String
sign = show . md5 . BS.pack . (++ s) . concatMap (uncurry (++)) . sortBy (compare `on` fst)
-- Insert desired response type into query
insertType ∷ ResponseType → [(String, String)] → [(String, String)]
insertType XML = id
insertType JSON = (("format", "json") :)
-- Try to find error message in Lastfm response
parseError ∷ ResponseType → ByteString → Maybe LastfmError
parseError XML = xmlError
parseError JSON = jsonError
query ∷ (ByteString → Maybe LastfmError) → [(String, String)] → IO (Either LastfmError Response)
query γ xs = do
(status, body) ← (respCurlCode &&& respBody) <$> curlResponse xs
return $ case status of
CurlOK → case γ body of
Nothing → Right body
Just n → Left n
s → Left $ CurlError s
curlResponse ∷ [(String, String)] → IO (CurlResponse_ [(String, String)] ByteString)
curlResponse xs = withCurlDo $ curlGetResponse_ "http://ws.audioscrobbler.com/2.0/?"
[ CurlPostFields . map (export . urlEncode) $ xs
, CurlFailOnError False
, CurlUserAgent "Mozilla/5.0 (X11; Linux x86_64; rv:10.0) Gecko/20100101 Firefox/10.0 Iceweasel/10.0"
, CurlConnectTimeout 10
]
-- Construct query parameter
(#) ∷ Argument a ⇒ a → (String, String)
(#) x = (key x, value x)