-- | This module contains the pypi REST client
module Pypi
  ( -- * Client
    PypiClient (baseUrl),
    withClient,

    -- * Api
    getProject,

    -- * Main data types
    PypiProject (..),
    getReleaseSemVer
  )
where

import Data.Aeson (FromJSON, decode, eitherDecode)
import Data.Maybe (fromJust)
import qualified Data.Text as T
import Data.Text (Text, unpack)
import Network.HTTP.Client
import Network.HTTP.Client.TLS (tlsManagerSettings)
import Pypi.Project

-- | The PypiClient record, use 'withClient' to create
data PypiClient
  = PypiClient
      { -- | the base url
        PypiClient -> Text
baseUrl :: Text,
        PypiClient -> Manager
manager :: Manager
      }

-- | Create the 'PypiClient'
withClient ::
  -- | The callback
  (PypiClient -> IO ()) ->
  -- | withClient performs the IO
  IO ()
withClient :: (PypiClient -> IO ()) -> IO ()
withClient callBack :: PypiClient -> IO ()
callBack =
  do
    Manager
manager <- ManagerSettings -> IO Manager
newManager ManagerSettings
tlsManagerSettings
    PypiClient -> IO ()
callBack (PypiClient :: Text -> Manager -> PypiClient
PypiClient {..})
  where
    baseUrl :: Text
baseUrl = "https://pypi.org/pypi/"

pypiGet ::
  (FromJSON a) =>
  Text ->
  PypiClient ->
  IO a
pypiGet :: Text -> PypiClient -> IO a
pypiGet path :: Text
path PypiClient {..} =
  do
    Request
request <- String -> IO Request
forall (m :: * -> *). MonadThrow m => String -> m Request
parseUrlThrow (Text -> String
unpack (Text -> String) -> Text -> String
forall a b. (a -> b) -> a -> b
$ Text
baseUrl Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
path)
    Response ByteString
response <- Request -> Manager -> IO (Response ByteString)
httpLbs Request
request Manager
manager
    case ByteString -> Either String a
forall a. FromJSON a => ByteString -> Either String a
eitherDecode (ByteString -> Either String a) -> ByteString -> Either String a
forall a b. (a -> b) -> a -> b
$ Response ByteString -> ByteString
forall body. Response body -> body
responseBody Response ByteString
response of
      Left err :: String
err -> String -> IO a
forall a. HasCallStack => String -> a
error (String -> IO a) -> String -> IO a
forall a b. (a -> b) -> a -> b
$ "Decoding of " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> ByteString -> String
forall a. Show a => a -> String
show (Response ByteString -> ByteString
forall body. Response body -> body
responseBody Response ByteString
response) String -> String -> String
forall a. Semigroup a => a -> a -> a
<> " failed with: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
err
      Right a :: a
a -> a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure a
a

-- | Get project infos
getProject :: Text -> PypiClient -> IO PypiProject
getProject :: Text -> PypiClient -> IO PypiProject
getProject project :: Text
project = Text -> PypiClient -> IO PypiProject
forall a. FromJSON a => Text -> PypiClient -> IO a
pypiGet (Text
project Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> "/json")