{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE GADTs #-} -- | Utility and base types and functions for the Discord Rest API module Discord.Internal.Rest.Prelude where import Prelude hiding (log) import Control.Exception.Safe (throwIO) import Control.Monad.IO.Class (MonadIO, liftIO) import Data.String (IsString(fromString)) import qualified Data.Text as T import qualified Data.Text.Encoding as TE import qualified Network.HTTP.Req as R import Web.Internal.HttpApiData (ToHttpApiData) import Discord.Internal.Types import Paths_discord_haskell (version) import Data.Version (showVersion) -- | The api version to use. apiVersion :: T.Text apiVersion = "10" -- | The base url (Req) for API requests baseUrl :: R.Url 'R.Https baseUrl = R.https "discord.com" R./: "api" R./: apiVersion' where apiVersion' = "v" <> apiVersion -- | Discord requires HTTP headers for authentication. authHeader :: Auth -> R.Option 'R.Https authHeader auth = R.header "Authorization" (TE.encodeUtf8 (authToken auth)) <> R.header "User-Agent" agent where -- | https://discord.com/developers/docs/reference#user-agent -- Second place where the library version is noted agent = fromString $ "DiscordBot (https://github.com/discord-haskell/discord-haskell, " <> showVersion version <> ")" -- Possibly append to an URL infixl 5 /? (/?) :: ToHttpApiData a => R.Url scheme -> Maybe a -> R.Url scheme (/?) url Nothing = url (/?) url (Just part) = url R./~ part -- | A compiled HTTP request ready to execute data JsonRequest where Delete :: R.Url 'R.Https -> R.Option 'R.Https -> JsonRequest Get :: R.Url 'R.Https -> R.Option 'R.Https -> JsonRequest Put :: R.HttpBody a => R.Url 'R.Https -> a -> R.Option 'R.Https -> JsonRequest Patch :: R.HttpBody a => R.Url 'R.Https -> RestIO a -> R.Option 'R.Https -> JsonRequest Post :: R.HttpBody a => R.Url 'R.Https -> RestIO a -> R.Option 'R.Https -> JsonRequest class Request a where -- | used for putting a request into a rate limit bucket -- https://discord.com/developers/docs/topics/rate-limits#rate-limits majorRoute :: a -> String -- | build a JSON http request jsonRequest :: a -> JsonRequest -- | Same Monad as IO. Overwrite Req settings newtype RestIO a = RestIO { restIOtoIO :: IO a } deriving (Functor, Applicative, Monad, MonadIO) instance R.MonadHttp RestIO where -- | Throw actual exceptions handleHttpException = liftIO . throwIO -- | Don't throw exceptions on http error codes like 404 getHttpConfig = pure $ R.defaultHttpConfig { R.httpConfigCheckResponse = \_ _ _ -> Nothing }