packages feed

gerrit-0.1.6.1: src/Gerrit/Client.hs

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}

-- | This module contains the internal gerrit REST client
module Gerrit.Client (
    GerritClient (baseUrl),
    withClient,
    gerritGet,
    gerritPost,
    getClient,
    getClientWithManager,
)
where

import Data.Aeson (FromJSON, ToJSON, eitherDecode, encode)
import qualified Data.ByteString.Lazy as BSL
import Data.Text (Text, unpack)
import qualified Data.Text as T
import qualified Data.Text.Encoding as T
import Network.HTTP.Client
import Network.HTTP.Client.OpenSSL (newOpenSSLManager, withOpenSSL)

-- | The GerritClient record, use 'withClient' to create
data GerritClient = GerritClient
    { baseUrl :: Text
    , manager :: Manager
    , auth :: Maybe (Text, Text)
    }

-- | Need to be call through withOpenSSL
getClient :: Text -> Maybe (Text, Text) -> IO GerritClient
getClient url auth = do
    manager <- newOpenSSLManager
    pure $ getClientWithManager manager url auth

-- | Creates a GerritClient with a provided http manager.
getClientWithManager :: Manager -> Text -> Maybe (Text, Text) -> GerritClient
getClientWithManager manager url auth =
    let baseUrl = T.dropWhileEnd (== '/') url <> "/"
     in GerritClient{..}

-- | Create the 'GerritClient'
withClient ::
    -- | The gerrit api url
    Text ->
    -- | Credentials (login, password) [Optional]
    Maybe (Text, Text) ->
    -- | The callback
    (GerritClient -> IO a) ->
    -- | withClient performs the IO
    IO a
withClient url creds callBack = withOpenSSL $ do
    client <- getClient url creds
    callBack client

gerritDecode :: (FromJSON a, Applicative f) => Response BSL.ByteString -> f a
gerritDecode response = case eitherDecode $ BSL.drop 5 $ responseBody response of
    Left err -> error $ "Decoding of " <> show (responseBody response) <> " failed with: " <> err
    Right a -> pure a

gerritRequest :: Text -> GerritClient -> IO Request
gerritRequest path GerritClient{..} =
    case auth of
        Just (user, pass) ->
            applyBasicAuth (T.encodeUtf8 user) (T.encodeUtf8 pass)
                <$> parseUrlThrow (unpack $ baseUrl <> "a/" <> path)
        Nothing -> parseUrlThrow (unpack $ baseUrl <> path)

gerritPost :: (ToJSON a, FromJSON b) => Text -> a -> GerritClient -> IO b
gerritPost path postData client@GerritClient{..} =
    do
        initRequest <- gerritRequest path client
        let request =
                initRequest
                    { method = "POST"
                    , requestHeaders = requestHeaders initRequest <> [("Content-Type", "application/json; charset=UTF-8")]
                    , requestBody = RequestBodyLBS $ encode postData
                    }
        response <- httpLbs request manager
        gerritDecode response

gerritGet :: (FromJSON a) => Text -> GerritClient -> IO a
gerritGet path client@GerritClient{..} =
    do
        request <- gerritRequest path client
        response <- httpLbs request manager
        gerritDecode response