mirror of
https://github.com/4cuck/teapawt.git
synced 2026-10-28 00:04:35 +00:00
config: take error messages as a list and rotate them
This commit is contained in:
1 parent
02ba12c9a9
commit
6943e19733
4 files changed
+46
-34
No files matched your search
@@ -82,6 +82,7 @@
|
||||
}:
|
||||
let
|
||||
cfg = config.services.teapot;
|
||||
messageType = lib.types.listOf lib.types.str;
|
||||
configFile = (pkgs.formats.toml { }).generate "teapot.toml" (
|
||||
lib.recursiveUpdate {
|
||||
inherit (cfg) cache preferences gifTranscoding;
|
||||
@@ -216,19 +217,23 @@
|
||||
'';
|
||||
};
|
||||
clientBudgetMessage = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
default = null;
|
||||
description = "Shown when a caller outruns its own budget.";
|
||||
type = messageType;
|
||||
default = [ ];
|
||||
example = [
|
||||
"Slow down."
|
||||
"Still too fast."
|
||||
];
|
||||
description = "Shown when a caller outruns its own budget. A list is rotated through.";
|
||||
};
|
||||
rateLimitedMessage = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
default = null;
|
||||
description = "Shown when the instance is out of upstream quota.";
|
||||
type = messageType;
|
||||
default = [ ];
|
||||
description = "Shown when the instance is out of upstream quota. A list is rotated through.";
|
||||
};
|
||||
internalErrorMessage = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
default = null;
|
||||
description = "Shown when a request fails for any other reason.";
|
||||
type = messageType;
|
||||
default = [ ];
|
||||
description = "Shown when a request fails for any other reason. A list is rotated through.";
|
||||
};
|
||||
proxy = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
|
||||
+3
-3
@@ -123,11 +123,11 @@ pub struct AppConfig {
|
||||
#[serde(default, rename = "trustedProxies")]
|
||||
pub trusted_proxies: Vec<String>,
|
||||
#[serde(default, rename = "rateLimitedMessage")]
|
||||
pub rate_limited_message: Option<String>,
|
||||
pub rate_limited_message: Vec<String>,
|
||||
#[serde(default, rename = "clientBudgetMessage")]
|
||||
pub client_budget_message: Option<String>,
|
||||
pub client_budget_message: Vec<String>,
|
||||
#[serde(default, rename = "internalErrorMessage")]
|
||||
pub internal_error_message: Option<String>,
|
||||
pub internal_error_message: Vec<String>,
|
||||
#[serde(default, rename = "enableDebug")]
|
||||
pub enable_debug: bool,
|
||||
#[serde(default, rename = "debugToken")]
|
||||
|
||||
+26
-19
@@ -1,7 +1,13 @@
|
||||
use std::{
|
||||
io,
|
||||
result,
|
||||
sync::OnceLock,
|
||||
sync::{
|
||||
OnceLock,
|
||||
atomic::{
|
||||
AtomicUsize,
|
||||
Ordering,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
use axum::{
|
||||
@@ -29,9 +35,9 @@ pub type Result<T> = result::Result<T, Error>;
|
||||
/// the two cannot drift.
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Messages {
|
||||
pub client_budget: Option<String>,
|
||||
pub rate_limited: Option<String>,
|
||||
pub internal_error: Option<String>,
|
||||
pub client_budget: Vec<String>,
|
||||
pub rate_limited: Vec<String>,
|
||||
pub internal_error: Vec<String>,
|
||||
}
|
||||
|
||||
static MESSAGES: OnceLock<Messages> = OnceLock::new();
|
||||
@@ -43,13 +49,23 @@ pub fn set_messages(messages: Messages) {
|
||||
|
||||
fn configured() -> &'static Messages {
|
||||
static EMPTY: Messages = Messages {
|
||||
client_budget: None,
|
||||
rate_limited: None,
|
||||
internal_error: None,
|
||||
client_budget: Vec::new(),
|
||||
rate_limited: Vec::new(),
|
||||
internal_error: Vec::new(),
|
||||
};
|
||||
MESSAGES.get().unwrap_or(&EMPTY)
|
||||
}
|
||||
|
||||
/// Rotate through the configured wordings, one per refusal.
|
||||
fn pick(configured: &'static [String], fallback: &'static str) -> &'static str {
|
||||
static NEXT: AtomicUsize = AtomicUsize::new(0);
|
||||
match *configured {
|
||||
[] => fallback,
|
||||
[ref only] => only,
|
||||
ref many => &many[NEXT.fetch_add(1, Ordering::Relaxed) % many.len()],
|
||||
}
|
||||
}
|
||||
|
||||
pub const CLIENT_BUDGET_MESSAGE: &str = "You are requesting uncached pages faster than this \
|
||||
instance can fetch them. Cached pages still work.";
|
||||
pub const RATE_LIMITED_MESSAGE: &str =
|
||||
@@ -59,18 +75,12 @@ pub const UNAVAILABLE_MESSAGE: &str = "The service has no available upstream ses
|
||||
|
||||
#[must_use]
|
||||
pub fn client_budget_message() -> &'static str {
|
||||
configured()
|
||||
.client_budget
|
||||
.as_deref()
|
||||
.unwrap_or(CLIENT_BUDGET_MESSAGE)
|
||||
pick(&configured().client_budget, CLIENT_BUDGET_MESSAGE)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn rate_limited_message() -> &'static str {
|
||||
configured()
|
||||
.rate_limited
|
||||
.as_deref()
|
||||
.unwrap_or(RATE_LIMITED_MESSAGE)
|
||||
pick(&configured().rate_limited, RATE_LIMITED_MESSAGE)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
@@ -80,10 +90,7 @@ pub const fn unavailable_message() -> &'static str {
|
||||
|
||||
#[must_use]
|
||||
pub fn internal_error_message() -> &'static str {
|
||||
configured()
|
||||
.internal_error
|
||||
.as_deref()
|
||||
.unwrap_or(INTERNAL_ERROR_MESSAGE)
|
||||
pick(&configured().internal_error, INTERNAL_ERROR_MESSAGE)
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
|
||||
@@ -41,9 +41,9 @@ fn test_config() -> Config {
|
||||
enable_rss: true,
|
||||
client_budget: false,
|
||||
trusted_proxies: Vec::new(),
|
||||
client_budget_message: None,
|
||||
rate_limited_message: None,
|
||||
internal_error_message: None,
|
||||
client_budget_message: Vec::new(),
|
||||
rate_limited_message: Vec::new(),
|
||||
internal_error_message: Vec::new(),
|
||||
enable_debug: false,
|
||||
debug_token: String::new(),
|
||||
proxy: String::new(),
|
||||
|
||||
Reference in new issue
Block a user