packages feed

gerrit-0.1.3.0: 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,
  )
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
  let baseUrl = T.dropWhileEnd (== '/') url <> "/"
  manager <- newOpenSSLManager
  pure $ 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