-- | Core shared by clients {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} {-# OPTIONS_GHC -fno-warn-orphans #-} module Blockfrost.Client.Core ( BlockfrostError (..) , Paged (..) , SortOrder (..) , asc , def , desc , fromServantClientError , newEnvByProject , page , paged , allPages , projectFromEnv , projectFromEnv' , projectFromFile ) where import Blockfrost.API (Form (..)) import Blockfrost.Auth import Blockfrost.Client.Auth () import Blockfrost.Client.Pagination import Blockfrost.Client.Sorting import Blockfrost.Client.Tag () import Blockfrost.Client.UserAgent () import Blockfrost.Types.ApiError import Data.Aeson (eitherDecode) import Data.Default (Default (def)) import Data.Text (Text) import qualified Data.Text.IO import qualified Network.HTTP.Client import qualified Network.HTTP.Client.TLS import Network.HTTP.Types import Servant.Client import Servant.Multipart.API import Servant.Multipart.Client () import qualified System.Environment domain :: String domain = "blockfrost.io" newEnvByProject :: Project -> IO ClientEnv newEnvByProject prj = do conman <- Network.HTTP.Client.newManager Network.HTTP.Client.TLS.tlsManagerSettings pure $ mkClientEnv conman (baseUrlByEnv $ projectEnv prj) buildUrl :: String -> BaseUrl buildUrl subdomain = BaseUrl Https (subdomain <> "." <> domain) 443 mempty baseUrlByEnv :: Env -> BaseUrl baseUrlByEnv Localhost = BaseUrl Http "localhost" 8000 "" baseUrlByEnv e = maybe (error "absurd") buildUrl (subdomainByEnv e) subdomainByEnv :: Env -> Maybe String subdomainByEnv Ipfs = pure "ipfs" subdomainByEnv Mainnet = pure "cardano-mainnet" subdomainByEnv Testnet = pure "cardano-testnet" subdomainByEnv Localhost = Nothing -- | Read file according to BLOCKFROST_TOKEN_PATH environment variable name. projectFromEnv :: IO Project projectFromEnv = projectFromEnv' "BLOCKFROST_TOKEN_PATH" -- | Read file according to environment variable name. projectFromEnv' :: String -> IO Project projectFromEnv' envVarName = do tokPath <- System.Environment.getEnv envVarName projectFromFile tokPath -- | Read file with token and turn it into @Project@ -- Expects tokens prefixed with environment, e.g. -- @testnetA3C2E...@ projectFromFile :: FilePath -> IO Project projectFromFile f = mkProject <$> Data.Text.IO.readFile f data BlockfrostError = BlockfrostError Text | BlockfrostBadRequest Text -- 400 | BlockfrostTokenMissing Text -- 403 | BlockfrostNotFound -- 404 | BlockfrostIPBanned -- 418 | BlockfrostUsageLimitReached -- 429 | BlockfrostFatal Text -- 500 | ServantClientError ClientError deriving (Eq, Show) fromServantClientError :: ClientError -> BlockfrostError fromServantClientError e = case e of FailureResponse _bUrl (Response s _ _ body) | s == status400 -> BlockfrostBadRequest (withMessage body) | s == status403 -> BlockfrostTokenMissing (withMessage body) | s == status404 -> BlockfrostNotFound | s == status418 -> BlockfrostIPBanned | s == status429 -> BlockfrostUsageLimitReached | s == status500 -> BlockfrostFatal (withMessage body) | otherwise -> BlockfrostError (withMessage body) _ -> ServantClientError e where withMessage body = case eitherDecode body of (Right (ae :: ApiError)) -> apiErrorMessage ae _ -> mempty instance ToMultipart Tmp Form where toMultipart (Form fileName filePath) = MultipartData mempty -- no text fields [ FileData "file" fileName "application/octet-stream" filePath ]