{-# LANGUAGE OverloadedStrings #-}
module Control.Shell.Download
( URI
, fetch, fetchBytes
, fetchFile
, fetchTags, fetchXML, fetchFeed
) where
import Data.ByteString as BS (ByteString, writeFile)
import Data.ByteString.UTF8 as BS
import Data.ByteString.Lazy as LBS
import Data.ByteString.Lazy.UTF8 as LBS
import Data.String
import Network.HTTP.Simple
import Network.HTTP.Types
import Text.Feed.Import (parseFeedString)
import Text.Feed.Types (Feed)
import Text.HTML.TagSoup (Tag, parseTags)
import Text.XML.Light (Content, parseXML)
import Control.Shell
type URI = String
liftE :: Show e => IO (Either e a) -> Shell a
liftE m = do
res <- liftIO m
case res of
Left e -> fail (show e)
Right x -> return x
httpFail :: Int -> BS.ByteString -> Shell a
httpFail code reason =
fail $ "HTTP error " ++ show code ++ ": " ++ BS.toString reason
fetchSomething :: URI -> Shell LBS.ByteString
fetchSomething uri = do
req <- assert ("could not parse URI `" ++ uri ++ "'") $ do
try $ liftIO $ parseRequest uri
rsp <- httpLBS req
case getResponseStatus rsp of
(Status 200 _) -> return (getResponseBody rsp)
(Status code reason) -> httpFail code reason
fetchBytes :: URI -> Shell BS.ByteString
fetchBytes = fmap LBS.toStrict . fetchSomething
fetch :: URI -> Shell String
fetch = fmap LBS.toString . fetchSomething
fetchFile :: FilePath -> URI -> Shell ()
fetchFile file = fetchSomething >=> liftIO . LBS.writeFile file
fetchTags :: URI -> Shell [Tag String]
fetchTags = fmap parseTags . fetch
fetchXML :: URI -> Shell [Content]
fetchXML = fmap parseXML . fetch
fetchFeed :: URI -> Shell Feed
fetchFeed uri = do
str <- LBS.toString <$> fetchSomething uri
assert ("could not parse feed from `" ++ uri ++ "'") (parseFeedString str)