module Ecluse.Core.Server.Response (
ServeDecision (..),
Rejection (..),
RejectReason (..),
Transience (..),
RetryAfter (..),
RuleName (..),
serveDecisionOf,
ArtifactStatus (..),
artifactStatus,
artifactStatusCode,
PackumentStatus (..),
packumentStatus,
packumentStatusCode,
longestRetry,
HelpMessage,
mkHelpMessage,
unHelpMessage,
appendHelp,
RenderedBody (..),
MountRenderer (..),
) where
import Data.Semigroup (Max (Max, getMax))
import Data.Text qualified as T
import Ecluse.Core.Package (PackageDetails)
import Ecluse.Core.Rules (renderDecision)
import Ecluse.Core.Rules.Types (
Decision (Admitted, Blocked, BlockedByDefault, Undecidable),
RetryAfter (..),
Transience (..),
)
data ServeDecision
=
Admit
|
Reject Rejection
deriving stock (ServeDecision -> ServeDecision -> Bool
(ServeDecision -> ServeDecision -> Bool)
-> (ServeDecision -> ServeDecision -> Bool) -> Eq ServeDecision
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: ServeDecision -> ServeDecision -> Bool
== :: ServeDecision -> ServeDecision -> Bool
$c/= :: ServeDecision -> ServeDecision -> Bool
/= :: ServeDecision -> ServeDecision -> Bool
Eq, Int -> ServeDecision -> ShowS
[ServeDecision] -> ShowS
ServeDecision -> String
(Int -> ServeDecision -> ShowS)
-> (ServeDecision -> String)
-> ([ServeDecision] -> ShowS)
-> Show ServeDecision
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> ServeDecision -> ShowS
showsPrec :: Int -> ServeDecision -> ShowS
$cshow :: ServeDecision -> String
show :: ServeDecision -> String
$cshowList :: [ServeDecision] -> ShowS
showList :: [ServeDecision] -> ShowS
Show)
data Rejection = Rejection
{ Rejection -> RejectReason
rejectionReason :: RejectReason
, Rejection -> Text
rejectionMessage :: Text
}
deriving stock (Rejection -> Rejection -> Bool
(Rejection -> Rejection -> Bool)
-> (Rejection -> Rejection -> Bool) -> Eq Rejection
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Rejection -> Rejection -> Bool
== :: Rejection -> Rejection -> Bool
$c/= :: Rejection -> Rejection -> Bool
/= :: Rejection -> Rejection -> Bool
Eq, Int -> Rejection -> ShowS
[Rejection] -> ShowS
Rejection -> String
(Int -> Rejection -> ShowS)
-> (Rejection -> String)
-> ([Rejection] -> ShowS)
-> Show Rejection
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Rejection -> ShowS
showsPrec :: Int -> Rejection -> ShowS
$cshow :: Rejection -> String
show :: Rejection -> String
$cshowList :: [Rejection] -> ShowS
showList :: [Rejection] -> ShowS
Show)
data RejectReason
=
ByPolicy RuleName
|
Unavailable Transience
|
MissingIntegrity
|
BelowIntegrityFloor
|
UpstreamInvalid
deriving stock (RejectReason -> RejectReason -> Bool
(RejectReason -> RejectReason -> Bool)
-> (RejectReason -> RejectReason -> Bool) -> Eq RejectReason
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: RejectReason -> RejectReason -> Bool
== :: RejectReason -> RejectReason -> Bool
$c/= :: RejectReason -> RejectReason -> Bool
/= :: RejectReason -> RejectReason -> Bool
Eq, Int -> RejectReason -> ShowS
[RejectReason] -> ShowS
RejectReason -> String
(Int -> RejectReason -> ShowS)
-> (RejectReason -> String)
-> ([RejectReason] -> ShowS)
-> Show RejectReason
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> RejectReason -> ShowS
showsPrec :: Int -> RejectReason -> ShowS
$cshow :: RejectReason -> String
show :: RejectReason -> String
$cshowList :: [RejectReason] -> ShowS
showList :: [RejectReason] -> ShowS
Show)
newtype RuleName = RuleName Text
deriving stock (RuleName -> RuleName -> Bool
(RuleName -> RuleName -> Bool)
-> (RuleName -> RuleName -> Bool) -> Eq RuleName
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: RuleName -> RuleName -> Bool
== :: RuleName -> RuleName -> Bool
$c/= :: RuleName -> RuleName -> Bool
/= :: RuleName -> RuleName -> Bool
Eq, Eq RuleName
Eq RuleName =>
(RuleName -> RuleName -> Ordering)
-> (RuleName -> RuleName -> Bool)
-> (RuleName -> RuleName -> Bool)
-> (RuleName -> RuleName -> Bool)
-> (RuleName -> RuleName -> Bool)
-> (RuleName -> RuleName -> RuleName)
-> (RuleName -> RuleName -> RuleName)
-> Ord RuleName
RuleName -> RuleName -> Bool
RuleName -> RuleName -> Ordering
RuleName -> RuleName -> RuleName
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: RuleName -> RuleName -> Ordering
compare :: RuleName -> RuleName -> Ordering
$c< :: RuleName -> RuleName -> Bool
< :: RuleName -> RuleName -> Bool
$c<= :: RuleName -> RuleName -> Bool
<= :: RuleName -> RuleName -> Bool
$c> :: RuleName -> RuleName -> Bool
> :: RuleName -> RuleName -> Bool
$c>= :: RuleName -> RuleName -> Bool
>= :: RuleName -> RuleName -> Bool
$cmax :: RuleName -> RuleName -> RuleName
max :: RuleName -> RuleName -> RuleName
$cmin :: RuleName -> RuleName -> RuleName
min :: RuleName -> RuleName -> RuleName
Ord, Int -> RuleName -> ShowS
[RuleName] -> ShowS
RuleName -> String
(Int -> RuleName -> ShowS)
-> (RuleName -> String) -> ([RuleName] -> ShowS) -> Show RuleName
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> RuleName -> ShowS
showsPrec :: Int -> RuleName -> ShowS
$cshow :: RuleName -> String
show :: RuleName -> String
$cshowList :: [RuleName] -> ShowS
showList :: [RuleName] -> ShowS
Show)
serveDecisionOf :: PackageDetails -> Decision -> ServeDecision
serveDecisionOf :: PackageDetails -> Decision -> ServeDecision
serveDecisionOf PackageDetails
pd Decision
decision = case Decision
decision of
Admitted{} -> ServeDecision
Admit
Blocked Text
name Text
_ -> Rejection -> ServeDecision
Reject (RejectReason -> Rejection
rejectAs (RuleName -> RejectReason
ByPolicy (Text -> RuleName
RuleName Text
name)))
BlockedByDefault{} -> Rejection -> ServeDecision
Reject (RejectReason -> Rejection
rejectAs (RuleName -> RejectReason
ByPolicy (Text -> RuleName
RuleName Text
"BlockedByDefault")))
Undecidable Transience
transience Text
_ -> Rejection -> ServeDecision
Reject (RejectReason -> Rejection
rejectAs (Transience -> RejectReason
Unavailable Transience
transience))
where
rejectAs :: RejectReason -> Rejection
rejectAs :: RejectReason -> Rejection
rejectAs RejectReason
reason = RejectReason -> Text -> Rejection
Rejection RejectReason
reason (PackageDetails -> Decision -> Text
renderDecision PackageDetails
pd Decision
decision)
data ArtifactStatus
=
Ok
|
Forbidden
|
Unavailable' (Maybe RetryAfter)
|
ServerError
|
NotFound
deriving stock (ArtifactStatus -> ArtifactStatus -> Bool
(ArtifactStatus -> ArtifactStatus -> Bool)
-> (ArtifactStatus -> ArtifactStatus -> Bool) -> Eq ArtifactStatus
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: ArtifactStatus -> ArtifactStatus -> Bool
== :: ArtifactStatus -> ArtifactStatus -> Bool
$c/= :: ArtifactStatus -> ArtifactStatus -> Bool
/= :: ArtifactStatus -> ArtifactStatus -> Bool
Eq, Int -> ArtifactStatus -> ShowS
[ArtifactStatus] -> ShowS
ArtifactStatus -> String
(Int -> ArtifactStatus -> ShowS)
-> (ArtifactStatus -> String)
-> ([ArtifactStatus] -> ShowS)
-> Show ArtifactStatus
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> ArtifactStatus -> ShowS
showsPrec :: Int -> ArtifactStatus -> ShowS
$cshow :: ArtifactStatus -> String
show :: ArtifactStatus -> String
$cshowList :: [ArtifactStatus] -> ShowS
showList :: [ArtifactStatus] -> ShowS
Show)
artifactStatus :: ServeDecision -> ArtifactStatus
artifactStatus :: ServeDecision -> ArtifactStatus
artifactStatus = \case
ServeDecision
Admit -> ArtifactStatus
Ok
Reject Rejection
rej -> case Rejection -> RejectReason
rejectionReason Rejection
rej of
ByPolicy{} -> ArtifactStatus
Forbidden
RejectReason
MissingIntegrity -> ArtifactStatus
Forbidden
RejectReason
BelowIntegrityFloor -> ArtifactStatus
Forbidden
Unavailable (WillResolve Maybe RetryAfter
retryAfter) -> Maybe RetryAfter -> ArtifactStatus
Unavailable' Maybe RetryAfter
retryAfter
Unavailable Transience
WontResolve -> ArtifactStatus
ServerError
RejectReason
UpstreamInvalid -> ArtifactStatus
ServerError
artifactStatusCode :: ArtifactStatus -> Int
artifactStatusCode :: ArtifactStatus -> Int
artifactStatusCode = \case
ArtifactStatus
Ok -> Int
200
ArtifactStatus
Forbidden -> Int
403
Unavailable'{} -> Int
503
ArtifactStatus
ServerError -> Int
500
ArtifactStatus
NotFound -> Int
404
data PackumentStatus
=
PackumentOk
|
PackumentForbidden
|
PackumentUnavailable (Maybe RetryAfter)
|
PackumentBadGateway
|
PackumentServerError
deriving stock (PackumentStatus -> PackumentStatus -> Bool
(PackumentStatus -> PackumentStatus -> Bool)
-> (PackumentStatus -> PackumentStatus -> Bool)
-> Eq PackumentStatus
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: PackumentStatus -> PackumentStatus -> Bool
== :: PackumentStatus -> PackumentStatus -> Bool
$c/= :: PackumentStatus -> PackumentStatus -> Bool
/= :: PackumentStatus -> PackumentStatus -> Bool
Eq, Int -> PackumentStatus -> ShowS
[PackumentStatus] -> ShowS
PackumentStatus -> String
(Int -> PackumentStatus -> ShowS)
-> (PackumentStatus -> String)
-> ([PackumentStatus] -> ShowS)
-> Show PackumentStatus
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> PackumentStatus -> ShowS
showsPrec :: Int -> PackumentStatus -> ShowS
$cshow :: PackumentStatus -> String
show :: PackumentStatus -> String
$cshowList :: [PackumentStatus] -> ShowS
showList :: [PackumentStatus] -> ShowS
Show)
packumentStatus :: [ServeDecision] -> PackumentStatus
packumentStatus :: [ServeDecision] -> PackumentStatus
packumentStatus [ServeDecision]
decisions
| PackumentTally -> Bool
tallyAdmit PackumentTally
tally = PackumentStatus
PackumentOk
| Bool -> Bool
not ([Maybe RetryAfter] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Maybe RetryAfter]
willResolveDelays) = Maybe RetryAfter -> PackumentStatus
PackumentUnavailable ([Maybe RetryAfter] -> Maybe RetryAfter
longestRetry [Maybe RetryAfter]
willResolveDelays)
| PackumentTally -> Bool
tallyUpstreamInvalid PackumentTally
tally = PackumentStatus
PackumentBadGateway
| PackumentTally -> Bool
tallyWontResolve PackumentTally
tally = PackumentStatus
PackumentServerError
| Bool
otherwise = PackumentStatus
PackumentForbidden
where
tally :: PackumentTally
tally :: PackumentTally
tally = (PackumentTally -> ServeDecision -> PackumentTally)
-> PackumentTally -> [ServeDecision] -> PackumentTally
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' PackumentTally -> ServeDecision -> PackumentTally
weigh (Bool -> [Maybe RetryAfter] -> Bool -> Bool -> PackumentTally
PackumentTally Bool
False [] Bool
False Bool
False) [ServeDecision]
decisions
willResolveDelays :: [Maybe RetryAfter]
willResolveDelays :: [Maybe RetryAfter]
willResolveDelays = PackumentTally -> [Maybe RetryAfter]
tallyWillResolveDelays PackumentTally
tally
weigh :: PackumentTally -> ServeDecision -> PackumentTally
weigh :: PackumentTally -> ServeDecision -> PackumentTally
weigh PackumentTally
acc = \case
ServeDecision
Admit -> PackumentTally
acc{tallyAdmit = True}
Reject Rejection
rej -> case Rejection -> RejectReason
rejectionReason Rejection
rej of
Unavailable (WillResolve Maybe RetryAfter
delay) ->
PackumentTally
acc{tallyWillResolveDelays = delay : tallyWillResolveDelays acc}
RejectReason
UpstreamInvalid -> PackumentTally
acc{tallyUpstreamInvalid = True}
Unavailable Transience
WontResolve -> PackumentTally
acc{tallyWontResolve = True}
ByPolicy{} -> PackumentTally
acc
RejectReason
MissingIntegrity -> PackumentTally
acc
RejectReason
BelowIntegrityFloor -> PackumentTally
acc
data PackumentTally = PackumentTally
{ PackumentTally -> Bool
tallyAdmit :: Bool
, PackumentTally -> [Maybe RetryAfter]
tallyWillResolveDelays :: [Maybe RetryAfter]
, PackumentTally -> Bool
tallyUpstreamInvalid :: Bool
, PackumentTally -> Bool
tallyWontResolve :: Bool
}
longestRetry :: [Maybe RetryAfter] -> Maybe RetryAfter
longestRetry :: [Maybe RetryAfter] -> Maybe RetryAfter
longestRetry = (Max RetryAfter -> RetryAfter)
-> Maybe (Max RetryAfter) -> Maybe RetryAfter
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Max RetryAfter -> RetryAfter
forall a. Max a -> a
getMax (Maybe (Max RetryAfter) -> Maybe RetryAfter)
-> ([Maybe RetryAfter] -> Maybe (Max RetryAfter))
-> [Maybe RetryAfter]
-> Maybe RetryAfter
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Maybe RetryAfter -> Maybe (Max RetryAfter))
-> [Maybe RetryAfter] -> Maybe (Max RetryAfter)
forall m a. Monoid m => (a -> m) -> [a] -> m
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap ((RetryAfter -> Max RetryAfter)
-> Maybe RetryAfter -> Maybe (Max RetryAfter)
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap RetryAfter -> Max RetryAfter
forall a. a -> Max a
Max)
packumentStatusCode :: PackumentStatus -> Int
packumentStatusCode :: PackumentStatus -> Int
packumentStatusCode = \case
PackumentStatus
PackumentOk -> Int
200
PackumentStatus
PackumentForbidden -> Int
403
PackumentUnavailable{} -> Int
503
PackumentStatus
PackumentBadGateway -> Int
502
PackumentStatus
PackumentServerError -> Int
500
newtype HelpMessage = HelpMessage Text
deriving stock (HelpMessage -> HelpMessage -> Bool
(HelpMessage -> HelpMessage -> Bool)
-> (HelpMessage -> HelpMessage -> Bool) -> Eq HelpMessage
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: HelpMessage -> HelpMessage -> Bool
== :: HelpMessage -> HelpMessage -> Bool
$c/= :: HelpMessage -> HelpMessage -> Bool
/= :: HelpMessage -> HelpMessage -> Bool
Eq, Int -> HelpMessage -> ShowS
[HelpMessage] -> ShowS
HelpMessage -> String
(Int -> HelpMessage -> ShowS)
-> (HelpMessage -> String)
-> ([HelpMessage] -> ShowS)
-> Show HelpMessage
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> HelpMessage -> ShowS
showsPrec :: Int -> HelpMessage -> ShowS
$cshow :: HelpMessage -> String
show :: HelpMessage -> String
$cshowList :: [HelpMessage] -> ShowS
showList :: [HelpMessage] -> ShowS
Show)
mkHelpMessage :: Text -> HelpMessage
mkHelpMessage :: Text -> HelpMessage
mkHelpMessage = Text -> HelpMessage
HelpMessage (Text -> HelpMessage) -> (Text -> Text) -> Text -> HelpMessage
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text
T.strip
unHelpMessage :: HelpMessage -> Text
unHelpMessage :: HelpMessage -> Text
unHelpMessage (HelpMessage Text
t) = Text
t
appendHelp :: Maybe HelpMessage -> Text -> Text
appendHelp :: Maybe HelpMessage -> Text -> Text
appendHelp Maybe HelpMessage
help Text
message =
case Maybe HelpMessage
help of
Just (HelpMessage Text
h) | Bool -> Bool
not (Text -> Bool
T.null Text
h) -> Text -> Text
T.strip Text
message Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
h
Maybe HelpMessage
_ -> Text
message
data RenderedBody = RenderedBody
{ RenderedBody -> ByteString
renderedContentType :: ByteString
, RenderedBody -> LByteString
renderedBytes :: LByteString
}
deriving stock (RenderedBody -> RenderedBody -> Bool
(RenderedBody -> RenderedBody -> Bool)
-> (RenderedBody -> RenderedBody -> Bool) -> Eq RenderedBody
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: RenderedBody -> RenderedBody -> Bool
== :: RenderedBody -> RenderedBody -> Bool
$c/= :: RenderedBody -> RenderedBody -> Bool
/= :: RenderedBody -> RenderedBody -> Bool
Eq, Int -> RenderedBody -> ShowS
[RenderedBody] -> ShowS
RenderedBody -> String
(Int -> RenderedBody -> ShowS)
-> (RenderedBody -> String)
-> ([RenderedBody] -> ShowS)
-> Show RenderedBody
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> RenderedBody -> ShowS
showsPrec :: Int -> RenderedBody -> ShowS
$cshow :: RenderedBody -> String
show :: RenderedBody -> String
$cshowList :: [RenderedBody] -> ShowS
showList :: [RenderedBody] -> ShowS
Show)
newtype MountRenderer = MountRenderer
{ MountRenderer -> Maybe HelpMessage -> Text -> RenderedBody
renderError :: Maybe HelpMessage -> Text -> RenderedBody
}