module Mail.Hailgun.Communication ( getRequest , postRequest , toQueryParams , parseResponse ) where import Control.Arrow (second) import Control.Monad.Catch (MonadThrow (..)) import Control.Monad.IO.Class (MonadIO (..)) import Data.Aeson import qualified Data.ByteString.Char8 as BC import qualified Data.ByteString.Lazy.Char8 as BLC import Data.Foldable (foldMap) import Data.Monoid import Mail.Hailgun.Errors import Mail.Hailgun.Internal.Data import qualified Network.HTTP.Client as NC import Network.HTTP.Client.Internal (addProxy) import Network.HTTP.Client.MultipartFormData (Part (..), formDataBody) import qualified Network.HTTP.Types.Method as NM import qualified Network.HTTP.Types.Status as NT toQueryParams :: [(BC.ByteString, BC.ByteString)] -> [(BC.ByteString, Maybe BC.ByteString)] toQueryParams = fmap (second Just) getRequest :: (MonadThrow m) => String -> HailgunContext -> [(BC.ByteString, Maybe BC.ByteString)] -> m NC.Request getRequest url context queryParams = do initRequest <- NC.parseUrl url let request = appEndo (applyHailgunAuth context) $ initRequest { NC.method = NM.methodGet, NC.checkStatus = ignoreStatus } return $ NC.setQueryString queryParams request postRequest :: (MonadThrow m, MonadIO m) => String -> HailgunContext -> [Part] -> m NC.Request postRequest url context parts = do initRequest <- NC.parseUrl url let request = initRequest { NC.method = NM.methodPost, NC.checkStatus = ignoreStatus } requestWithBody <- formDataBody parts request --requestWithBody <- encodeFormData formParams request return $ appEndo (applyHailgunAuth context) requestWithBody applyHailgunAuth :: HailgunContext -> Endo NC.Request applyHailgunAuth context = addRequestProxy (hailgunProxy context) <> authRequest context addRequestProxy :: Maybe NC.Proxy -> Endo NC.Request addRequestProxy = foldMap addProxy' authRequest :: HailgunContext -> Endo NC.Request authRequest context = Endo $ NC.applyBasicAuth (BC.pack "api") (BC.pack . hailgunApiKey $ context) addProxy' :: NC.Proxy -> Endo NC.Request addProxy' proxy = Endo $ addProxy (NC.proxyHost proxy) (NC.proxyPort proxy) parseResponse :: (FromJSON a) => NC.Response BLC.ByteString -> Either HailgunErrorResponse a parseResponse response = statusToResponse . NT.statusCode . NC.responseStatus $ response where statusToResponse s | s == 200 = responseDecode response | s `elem` [400, 401, 402, 404] = gatherErrors . responseDecode $ response | s `elem` [500, 502, 503, 504] = serverError | otherwise = unexpectedError s responseDecode :: (FromJSON a) => NC.Response BLC.ByteString -> Either HailgunErrorResponse a responseDecode = mapError . eitherDecode . NC.responseBody ignoreStatus :: a -> b -> c -> Maybe d ignoreStatus _ _ _ = Nothing