elm-get-0.1: src/Utils/Http.hs
{-# LANGUAGE OverloadedStrings #-}
module Utils.Http where
import Network
import Network.HTTP
import Network.HTTP.Types
import Network.HTTP.Conduit
import Control.Monad.Error
import Control.Monad.Trans.Resource
import qualified Control.Exception as E
import Data.Aeson as Json
import Data.Monoid ((<>))
import qualified Data.List as List
import qualified Data.Vector as Vector
import qualified Data.ByteString.Char8 as BSC
import qualified Elm.Internal.Name as N
import qualified Elm.Internal.Version as V
send :: String -> (Manager -> ResourceT IO a) -> ErrorT String IO a
send domain request =
do result <- liftIO $ E.catch (Right `fmap` mkRequest) handler
either throwError return result
where
mkRequest = withSocketsDo $ withManager request
handler exception =
case exception of
sce@(StatusCodeException (Status code err) headers _) ->
let details = case List.lookup "X-Response-Body-Start" headers of
Just msg | not (BSC.null msg) -> msg
_ -> err
in return . Left $ BSC.unpack details
_ -> return . Left $
"probably unable to connect to <" ++ domain ++ "> (" ++
show exception ++ ")"
githubTags :: N.Name -> ErrorT String IO Tags
githubTags name =
do response <- send "https://api.github.com" $ \manager -> do
request <- parseUrl url
httpLbs (request {requestHeaders = headers}) manager
case Json.eitherDecode $ responseBody response of
Left err -> throwError err
Right tags -> return tags
where
url = "https://api.github.com/repos/" ++ N.user name ++
"/" ++ N.project name ++ "/tags"
headers = [("User-Agent", "elm-get")] <>
[("Accept", "application/json")]
data Tags = Tags [String]
deriving Show
instance FromJSON Tags where
parseJSON (Array arr) = Tags `fmap` mapM toTag list
where
list = Vector.toList arr
toTag (Object obj) = obj .: "name"
toTag _ = fail "expecting an object"
parseJSON _ = fail "expecting an array"