{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE UndecidableInstances #-}
module Servant.RateLimit.Types (
RateLimit,
FixedWindow,
SlidingWindow,
HasRateLimitStrategy(..),
IPAddressPolicy,
HasRateLimitPolicy(..),
module Data.Time.TypeLevel
) where
import GHC.TypeLits
import Data.ByteString.Char8 as C8
import Data.Kind
import Data.Proxy
import qualified Data.Time.Units as Units
import Data.Time.TypeLevel
import Network.Wai
import Network.Wai.RateLimit.Backend
import Network.Wai.RateLimit.Strategy
data FixedWindow (dur :: TimePeriod) (capacity :: Nat)
data SlidingWindow (dur :: TimePeriod) (capacity :: Nat)
class HasRateLimitStrategy strategy where
strategyValue :: Backend key -> (Request -> IO key) -> Strategy
instance
(KnownDuration dur, KnownNat capacity, Units.TimeUnit (DurationUnit dur))
=> HasRateLimitStrategy (FixedWindow dur capacity)
where
strategyValue :: Backend key -> (Request -> IO key) -> Strategy
strategyValue Backend key
backend Request -> IO key
getKey = Backend key -> Second -> Integer -> (Request -> IO key) -> Strategy
forall key.
Backend key -> Second -> Integer -> (Request -> IO key) -> Strategy
fixedWindow
Backend key
backend
(DurationUnit dur -> Second
forall a b. (TimeUnit a, TimeUnit b) => a -> b
Units.convertUnit (DurationUnit dur -> Second) -> DurationUnit dur -> Second
forall a b. (a -> b) -> a -> b
$ KnownDuration dur => DurationUnit dur
forall k (k1 :: k). KnownDuration k1 => DurationUnit k1
durationVal @dur)
(Integer -> Integer
forall a. Num a => Integer -> a
fromInteger (Integer -> Integer) -> Integer -> Integer
forall a b. (a -> b) -> a -> b
$ Proxy capacity -> Integer
forall (n :: Nat) (proxy :: Nat -> *).
KnownNat n =>
proxy n -> Integer
natVal (Proxy capacity
forall k (t :: k). Proxy t
Proxy :: Proxy capacity))
Request -> IO key
getKey
instance
(KnownDuration dur, KnownNat capacity, Units.TimeUnit (DurationUnit dur))
=> HasRateLimitStrategy (SlidingWindow dur capacity)
where
strategyValue :: Backend key -> (Request -> IO key) -> Strategy
strategyValue Backend key
backend Request -> IO key
getKey = Backend key -> Second -> Integer -> (Request -> IO key) -> Strategy
forall key.
Backend key -> Second -> Integer -> (Request -> IO key) -> Strategy
slidingWindow
Backend key
backend
(DurationUnit dur -> Second
forall a b. (TimeUnit a, TimeUnit b) => a -> b
Units.convertUnit (DurationUnit dur -> Second) -> DurationUnit dur -> Second
forall a b. (a -> b) -> a -> b
$ KnownDuration dur => DurationUnit dur
forall k (k1 :: k). KnownDuration k1 => DurationUnit k1
durationVal @dur)
(Integer -> Integer
forall a. Num a => Integer -> a
fromInteger (Integer -> Integer) -> Integer -> Integer
forall a b. (a -> b) -> a -> b
$ Proxy capacity -> Integer
forall (n :: Nat) (proxy :: Nat -> *).
KnownNat n =>
proxy n -> Integer
natVal (Proxy capacity
forall k (t :: k). Proxy t
Proxy :: Proxy capacity))
Request -> IO key
getKey
data IPAddressPolicy (prefix :: Symbol)
class HasRateLimitPolicy policy where
type RateLimitPolicyKey policy :: Type
policyGetIdentifier :: Request -> IO (RateLimitPolicyKey policy)
instance KnownSymbol prefix => HasRateLimitPolicy (IPAddressPolicy prefix) where
type RateLimitPolicyKey (IPAddressPolicy prefix) = ByteString
policyGetIdentifier :: Request -> IO (RateLimitPolicyKey (IPAddressPolicy prefix))
policyGetIdentifier =
ByteString -> IO ByteString
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ByteString -> IO ByteString)
-> (Request -> ByteString) -> Request -> IO ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> ByteString
C8.pack (Proxy prefix -> String
forall (n :: Symbol) (proxy :: Symbol -> *).
KnownSymbol n =>
proxy n -> String
symbolVal (Proxy prefix
forall k (t :: k). Proxy t
Proxy :: Proxy prefix)) ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<>) (ByteString -> ByteString)
-> (Request -> ByteString) -> Request -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
String -> ByteString
C8.pack (String -> ByteString)
-> (Request -> String) -> Request -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SockAddr -> String
forall a. Show a => a -> String
show (SockAddr -> String) -> (Request -> SockAddr) -> Request -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Request -> SockAddr
remoteHost
data RateLimit strategy policy