mirror of
https://github.com/actix/actix-extras.git
synced 2024-11-23 23:51:06 +01:00
modululize -settings
This commit is contained in:
parent
e13b62fc6b
commit
f678842e46
@ -1,17 +1,31 @@
|
|||||||
use std::{fmt, path::PathBuf};
|
use serde::Deserialize;
|
||||||
|
|
||||||
use once_cell::sync::Lazy;
|
mod address;
|
||||||
use regex::Regex;
|
mod backlog;
|
||||||
use serde::{de, Deserialize};
|
mod keep_alive;
|
||||||
|
mod max_connection_rate;
|
||||||
|
mod max_connections;
|
||||||
|
mod mode;
|
||||||
|
mod num_workers;
|
||||||
|
mod timeout;
|
||||||
|
mod tls;
|
||||||
|
|
||||||
use crate::{core::Parse, error::AtError};
|
pub use self::address::Address;
|
||||||
|
pub use self::backlog::Backlog;
|
||||||
|
pub use self::keep_alive::KeepAlive;
|
||||||
|
pub use self::max_connection_rate::MaxConnectionRate;
|
||||||
|
pub use self::max_connections::MaxConnections;
|
||||||
|
pub use self::mode::Mode;
|
||||||
|
pub use self::num_workers::NumWorkers;
|
||||||
|
pub use self::timeout::Timeout;
|
||||||
|
pub use self::tls::Tls;
|
||||||
|
|
||||||
/// Settings types for Actix Web.
|
/// Settings types for Actix Web.
|
||||||
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize)]
|
||||||
#[serde(rename_all = "kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
pub struct ActixSettings {
|
pub struct ActixSettings {
|
||||||
pub hosts: Vec<Address>,
|
pub hosts: Vec<Address>,
|
||||||
pub mode: Mode,
|
pub mode: mode::Mode,
|
||||||
pub enable_compression: bool,
|
pub enable_compression: bool,
|
||||||
pub enable_log: bool,
|
pub enable_log: bool,
|
||||||
pub num_workers: NumWorkers,
|
pub num_workers: NumWorkers,
|
||||||
@ -24,489 +38,3 @@ pub struct ActixSettings {
|
|||||||
pub shutdown_timeout: Timeout,
|
pub shutdown_timeout: Timeout,
|
||||||
pub tls: Tls,
|
pub tls: Tls,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Hash)]
|
|
||||||
pub struct Address {
|
|
||||||
pub host: String,
|
|
||||||
pub port: u16,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) static ADDR_REGEX: Lazy<Regex> = Lazy::new(|| {
|
|
||||||
Regex::new(
|
|
||||||
r#"(?x)
|
|
||||||
\[ # opening square bracket
|
|
||||||
(\s)* # optional whitespace
|
|
||||||
"(?P<host>[^"]+)" # host name (string)
|
|
||||||
, # separating comma
|
|
||||||
(\s)* # optional whitespace
|
|
||||||
(?P<port>\d+) # port number (integer)
|
|
||||||
(\s)* # optional whitespace
|
|
||||||
\] # closing square bracket
|
|
||||||
"#,
|
|
||||||
)
|
|
||||||
.expect("Failed to compile regex: ADDR_REGEX")
|
|
||||||
});
|
|
||||||
|
|
||||||
pub(crate) static ADDR_LIST_REGEX: Lazy<Regex> = Lazy::new(|| {
|
|
||||||
Regex::new(
|
|
||||||
r#"(?x)
|
|
||||||
\[ # opening square bracket (list)
|
|
||||||
(\s)* # optional whitespace
|
|
||||||
(?P<elements>(
|
|
||||||
\[".*", (\s)* \d+\] # element
|
|
||||||
(,)? # element separator
|
|
||||||
(\s)* # optional whitespace
|
|
||||||
)*)
|
|
||||||
(\s)* # optional whitespace
|
|
||||||
\] # closing square bracket (list)
|
|
||||||
"#,
|
|
||||||
)
|
|
||||||
.expect("Failed to compile regex: ADDRS_REGEX")
|
|
||||||
});
|
|
||||||
|
|
||||||
impl Parse for Address {
|
|
||||||
fn parse(string: &str) -> Result<Self, AtError> {
|
|
||||||
let mut items = string
|
|
||||||
.trim()
|
|
||||||
.trim_start_matches('[')
|
|
||||||
.trim_end_matches(']')
|
|
||||||
.split(',');
|
|
||||||
|
|
||||||
let parse_error = || AtError::ParseAddressError(string.to_string());
|
|
||||||
|
|
||||||
if !ADDR_REGEX.is_match(string) {
|
|
||||||
return Err(parse_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
host: items.next().ok_or_else(parse_error)?.trim().to_string(),
|
|
||||||
port: items.next().ok_or_else(parse_error)?.trim().parse()?,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Parse for Vec<Address> {
|
|
||||||
fn parse(string: &str) -> Result<Self, AtError> {
|
|
||||||
let parse_error = || AtError::ParseAddressError(string.to_string());
|
|
||||||
|
|
||||||
if !ADDR_LIST_REGEX.is_match(string) {
|
|
||||||
return Err(parse_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut addrs = vec![];
|
|
||||||
|
|
||||||
for list_caps in ADDR_LIST_REGEX.captures_iter(string) {
|
|
||||||
let elements = &list_caps["elements"].trim();
|
|
||||||
for elt_caps in ADDR_REGEX.captures_iter(elements) {
|
|
||||||
addrs.push(Address {
|
|
||||||
host: elt_caps["host"].to_string(),
|
|
||||||
port: elt_caps["port"].parse()?,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(addrs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Hash)]
|
|
||||||
pub enum Mode {
|
|
||||||
#[serde(rename = "development")]
|
|
||||||
Development,
|
|
||||||
|
|
||||||
#[serde(rename = "production")]
|
|
||||||
Production,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Parse for Mode {
|
|
||||||
fn parse(string: &str) -> std::result::Result<Self, AtError> {
|
|
||||||
match string {
|
|
||||||
"development" => Ok(Self::Development),
|
|
||||||
"production" => Ok(Self::Production),
|
|
||||||
_ => Err(InvalidValue! {
|
|
||||||
expected: "\"development\" | \"production\".",
|
|
||||||
got: string,
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
||||||
pub enum NumWorkers {
|
|
||||||
Default,
|
|
||||||
Manual(usize),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Parse for NumWorkers {
|
|
||||||
fn parse(string: &str) -> std::result::Result<Self, AtError> {
|
|
||||||
match string {
|
|
||||||
"default" => Ok(NumWorkers::Default),
|
|
||||||
string => match string.parse::<usize>() {
|
|
||||||
Ok(val) => Ok(NumWorkers::Manual(val)),
|
|
||||||
Err(_) => Err(InvalidValue! {
|
|
||||||
expected: "a positive integer",
|
|
||||||
got: string,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de> serde::Deserialize<'de> for NumWorkers {
|
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
||||||
where
|
|
||||||
D: serde::Deserializer<'de>,
|
|
||||||
{
|
|
||||||
struct NumWorkersVisitor;
|
|
||||||
|
|
||||||
impl<'de> de::Visitor<'de> for NumWorkersVisitor {
|
|
||||||
type Value = NumWorkers;
|
|
||||||
|
|
||||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
let msg = "Either \"default\" or a string containing an integer > 0";
|
|
||||||
formatter.write_str(msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
|
||||||
where
|
|
||||||
E: de::Error,
|
|
||||||
{
|
|
||||||
match NumWorkers::parse(value) {
|
|
||||||
Ok(num_workers) => Ok(num_workers),
|
|
||||||
Err(AtError::InvalidValue { expected, got, .. }) => Err(
|
|
||||||
de::Error::invalid_value(de::Unexpected::Str(&got), &expected),
|
|
||||||
),
|
|
||||||
Err(_) => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deserializer.deserialize_string(NumWorkersVisitor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
||||||
pub enum Backlog {
|
|
||||||
Default,
|
|
||||||
Manual(usize),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Parse for Backlog {
|
|
||||||
fn parse(string: &str) -> std::result::Result<Self, AtError> {
|
|
||||||
match string {
|
|
||||||
"default" => Ok(Backlog::Default),
|
|
||||||
string => match string.parse::<usize>() {
|
|
||||||
Ok(val) => Ok(Backlog::Manual(val)),
|
|
||||||
Err(_) => Err(InvalidValue! {
|
|
||||||
expected: "an integer > 0",
|
|
||||||
got: string,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de> serde::Deserialize<'de> for Backlog {
|
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
||||||
where
|
|
||||||
D: serde::Deserializer<'de>,
|
|
||||||
{
|
|
||||||
struct BacklogVisitor;
|
|
||||||
|
|
||||||
impl<'de> de::Visitor<'de> for BacklogVisitor {
|
|
||||||
type Value = Backlog;
|
|
||||||
|
|
||||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
let msg = "Either \"default\" or a string containing an integer > 0";
|
|
||||||
formatter.write_str(msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
|
||||||
where
|
|
||||||
E: de::Error,
|
|
||||||
{
|
|
||||||
match Backlog::parse(value) {
|
|
||||||
Ok(backlog) => Ok(backlog),
|
|
||||||
Err(AtError::InvalidValue { expected, got, .. }) => Err(
|
|
||||||
de::Error::invalid_value(de::Unexpected::Str(&got), &expected),
|
|
||||||
),
|
|
||||||
Err(_) => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deserializer.deserialize_string(BacklogVisitor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
||||||
pub enum MaxConnections {
|
|
||||||
Default,
|
|
||||||
Manual(usize),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Parse for MaxConnections {
|
|
||||||
fn parse(string: &str) -> std::result::Result<Self, AtError> {
|
|
||||||
match string {
|
|
||||||
"default" => Ok(MaxConnections::Default),
|
|
||||||
string => match string.parse::<usize>() {
|
|
||||||
Ok(val) => Ok(MaxConnections::Manual(val)),
|
|
||||||
Err(_) => Err(InvalidValue! {
|
|
||||||
expected: "an integer > 0",
|
|
||||||
got: string,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de> serde::Deserialize<'de> for MaxConnections {
|
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
||||||
where
|
|
||||||
D: serde::Deserializer<'de>,
|
|
||||||
{
|
|
||||||
struct MaxConnectionsVisitor;
|
|
||||||
|
|
||||||
impl<'de> de::Visitor<'de> for MaxConnectionsVisitor {
|
|
||||||
type Value = MaxConnections;
|
|
||||||
|
|
||||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
let msg = "Either \"default\" or a string containing an integer > 0";
|
|
||||||
formatter.write_str(msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
|
||||||
where
|
|
||||||
E: de::Error,
|
|
||||||
{
|
|
||||||
match MaxConnections::parse(value) {
|
|
||||||
Ok(max_connections) => Ok(max_connections),
|
|
||||||
Err(AtError::InvalidValue { expected, got, .. }) => Err(
|
|
||||||
de::Error::invalid_value(de::Unexpected::Str(&got), &expected),
|
|
||||||
),
|
|
||||||
Err(_) => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deserializer.deserialize_string(MaxConnectionsVisitor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
||||||
pub enum MaxConnectionRate {
|
|
||||||
Default,
|
|
||||||
Manual(usize),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Parse for MaxConnectionRate {
|
|
||||||
fn parse(string: &str) -> std::result::Result<Self, AtError> {
|
|
||||||
match string {
|
|
||||||
"default" => Ok(MaxConnectionRate::Default),
|
|
||||||
string => match string.parse::<usize>() {
|
|
||||||
Ok(val) => Ok(MaxConnectionRate::Manual(val)),
|
|
||||||
Err(_) => Err(InvalidValue! {
|
|
||||||
expected: "an integer > 0",
|
|
||||||
got: string,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de> serde::Deserialize<'de> for MaxConnectionRate {
|
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
||||||
where
|
|
||||||
D: serde::Deserializer<'de>,
|
|
||||||
{
|
|
||||||
struct MaxConnectionRateVisitor;
|
|
||||||
|
|
||||||
impl<'de> de::Visitor<'de> for MaxConnectionRateVisitor {
|
|
||||||
type Value = MaxConnectionRate;
|
|
||||||
|
|
||||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
let msg = "Either \"default\" or a string containing an integer > 0";
|
|
||||||
formatter.write_str(msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
|
||||||
where
|
|
||||||
E: de::Error,
|
|
||||||
{
|
|
||||||
match MaxConnectionRate::parse(value) {
|
|
||||||
Ok(max_connection_rate) => Ok(max_connection_rate),
|
|
||||||
Err(AtError::InvalidValue { expected, got, .. }) => Err(
|
|
||||||
de::Error::invalid_value(de::Unexpected::Str(&got), &expected),
|
|
||||||
),
|
|
||||||
Err(_) => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deserializer.deserialize_string(MaxConnectionRateVisitor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
||||||
pub enum KeepAlive {
|
|
||||||
Default,
|
|
||||||
Disabled,
|
|
||||||
Os,
|
|
||||||
Seconds(usize),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Parse for KeepAlive {
|
|
||||||
fn parse(string: &str) -> std::result::Result<Self, AtError> {
|
|
||||||
pub(crate) static FMT: Lazy<Regex> =
|
|
||||||
Lazy::new(|| Regex::new(r"^\d+ seconds$").expect("Failed to compile regex: FMT"));
|
|
||||||
|
|
||||||
pub(crate) static DIGITS: Lazy<Regex> =
|
|
||||||
Lazy::new(|| Regex::new(r"^\d+").expect("Failed to compile regex: FMT"));
|
|
||||||
|
|
||||||
macro_rules! invalid_value {
|
|
||||||
($got:expr) => {
|
|
||||||
Err(InvalidValue! {
|
|
||||||
expected: "a string of the format \"N seconds\" where N is an integer > 0",
|
|
||||||
got: $got,
|
|
||||||
})
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
let digits_in = |m: regex::Match| &string[m.start()..m.end()];
|
|
||||||
match string {
|
|
||||||
"default" => Ok(KeepAlive::Default),
|
|
||||||
"disabled" => Ok(KeepAlive::Disabled),
|
|
||||||
"OS" | "os" => Ok(KeepAlive::Os),
|
|
||||||
string if !FMT.is_match(string) => invalid_value!(string),
|
|
||||||
string => match DIGITS.find(string) {
|
|
||||||
None => invalid_value!(string),
|
|
||||||
Some(mat) => match digits_in(mat).parse() {
|
|
||||||
Ok(val) => Ok(KeepAlive::Seconds(val)),
|
|
||||||
Err(_) => invalid_value!(string),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de> serde::Deserialize<'de> for KeepAlive {
|
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
||||||
where
|
|
||||||
D: serde::Deserializer<'de>,
|
|
||||||
{
|
|
||||||
struct KeepAliveVisitor;
|
|
||||||
|
|
||||||
impl<'de> de::Visitor<'de> for KeepAliveVisitor {
|
|
||||||
type Value = KeepAlive;
|
|
||||||
|
|
||||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
let msg = "Either \"default\", \"disabled\", \"os\", or a string of the format \"N seconds\" where N is an integer > 0";
|
|
||||||
formatter.write_str(msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
|
||||||
where
|
|
||||||
E: de::Error,
|
|
||||||
{
|
|
||||||
match KeepAlive::parse(value) {
|
|
||||||
Ok(keep_alive) => Ok(keep_alive),
|
|
||||||
Err(AtError::InvalidValue { expected, got, .. }) => Err(
|
|
||||||
de::Error::invalid_value(de::Unexpected::Str(&got), &expected),
|
|
||||||
),
|
|
||||||
Err(_) => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deserializer.deserialize_string(KeepAliveVisitor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
||||||
pub enum Timeout {
|
|
||||||
Default,
|
|
||||||
Milliseconds(usize),
|
|
||||||
Seconds(usize),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Parse for Timeout {
|
|
||||||
fn parse(string: &str) -> std::result::Result<Self, AtError> {
|
|
||||||
pub static FMT: Lazy<Regex> = Lazy::new(|| {
|
|
||||||
Regex::new(r"^\d+ (milliseconds|seconds)$").expect("Failed to compile regex: FMT")
|
|
||||||
});
|
|
||||||
|
|
||||||
pub static DIGITS: Lazy<Regex> =
|
|
||||||
Lazy::new(|| Regex::new(r"^\d+").expect("Failed to compile regex: DIGITS"));
|
|
||||||
|
|
||||||
pub static UNIT: Lazy<Regex> = Lazy::new(|| {
|
|
||||||
Regex::new(r"(milliseconds|seconds)$").expect("Failed to compile regex: UNIT")
|
|
||||||
});
|
|
||||||
|
|
||||||
macro_rules! invalid_value {
|
|
||||||
($got:expr) => {
|
|
||||||
Err(InvalidValue! {
|
|
||||||
expected: "a string of the format \"N seconds\" or \"N milliseconds\" where N is an integer > 0",
|
|
||||||
got: $got,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
match string {
|
|
||||||
"default" => Ok(Timeout::Default),
|
|
||||||
string if !FMT.is_match(string) => invalid_value!(string),
|
|
||||||
string => match (DIGITS.find(string), UNIT.find(string)) {
|
|
||||||
(None, _) => invalid_value!(string),
|
|
||||||
(_, None) => invalid_value!(string),
|
|
||||||
(Some(dmatch), Some(umatch)) => {
|
|
||||||
let digits = &string[dmatch.start()..dmatch.end()];
|
|
||||||
let unit = &string[umatch.start()..umatch.end()];
|
|
||||||
match (digits.parse(), unit) {
|
|
||||||
(Ok(v), "milliseconds") => Ok(Timeout::Milliseconds(v)),
|
|
||||||
(Ok(v), "seconds") => Ok(Timeout::Seconds(v)),
|
|
||||||
_ => invalid_value!(string),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de> serde::Deserialize<'de> for Timeout {
|
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
||||||
where
|
|
||||||
D: serde::Deserializer<'de>,
|
|
||||||
{
|
|
||||||
struct TimeoutVisitor;
|
|
||||||
|
|
||||||
impl<'de> de::Visitor<'de> for TimeoutVisitor {
|
|
||||||
type Value = Timeout;
|
|
||||||
|
|
||||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
let msg = "Either \"default\", \"disabled\", \"os\", or a string of the format \"N seconds\" where N is an integer > 0";
|
|
||||||
formatter.write_str(msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
|
||||||
where
|
|
||||||
E: de::Error,
|
|
||||||
{
|
|
||||||
match Timeout::parse(value) {
|
|
||||||
Ok(num_workers) => Ok(num_workers),
|
|
||||||
Err(AtError::InvalidValue { expected, got, .. }) => Err(
|
|
||||||
de::Error::invalid_value(de::Unexpected::Str(&got), &expected),
|
|
||||||
),
|
|
||||||
Err(_) => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deserializer.deserialize_string(TimeoutVisitor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Hash)]
|
|
||||||
#[serde(rename_all = "kebab-case")]
|
|
||||||
pub struct Tls {
|
|
||||||
pub enabled: bool,
|
|
||||||
pub certificate: PathBuf,
|
|
||||||
pub private_key: PathBuf,
|
|
||||||
}
|
|
||||||
|
89
actix-settings/src/actix/address.rs
Normal file
89
actix-settings/src/actix/address.rs
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
use once_cell::sync::Lazy;
|
||||||
|
use regex::Regex;
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
use crate::{core::Parse, error::AtError};
|
||||||
|
|
||||||
|
static ADDR_REGEX: Lazy<Regex> = Lazy::new(|| {
|
||||||
|
Regex::new(
|
||||||
|
r#"(?x)
|
||||||
|
\[ # opening square bracket
|
||||||
|
(\s)* # optional whitespace
|
||||||
|
"(?P<host>[^"]+)" # host name (string)
|
||||||
|
, # separating comma
|
||||||
|
(\s)* # optional whitespace
|
||||||
|
(?P<port>\d+) # port number (integer)
|
||||||
|
(\s)* # optional whitespace
|
||||||
|
\] # closing square bracket
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.expect("Failed to compile regex: ADDR_REGEX")
|
||||||
|
});
|
||||||
|
|
||||||
|
static ADDR_LIST_REGEX: Lazy<Regex> = Lazy::new(|| {
|
||||||
|
Regex::new(
|
||||||
|
r#"(?x)
|
||||||
|
\[ # opening square bracket (list)
|
||||||
|
(\s)* # optional whitespace
|
||||||
|
(?P<elements>(
|
||||||
|
\[".*", (\s)* \d+\] # element
|
||||||
|
(,)? # element separator
|
||||||
|
(\s)* # optional whitespace
|
||||||
|
)*)
|
||||||
|
(\s)* # optional whitespace
|
||||||
|
\] # closing square bracket (list)
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.expect("Failed to compile regex: ADDRS_REGEX")
|
||||||
|
});
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize)]
|
||||||
|
pub struct Address {
|
||||||
|
pub host: String,
|
||||||
|
pub port: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for Address {
|
||||||
|
fn parse(string: &str) -> Result<Self, AtError> {
|
||||||
|
let mut items = string
|
||||||
|
.trim()
|
||||||
|
.trim_start_matches('[')
|
||||||
|
.trim_end_matches(']')
|
||||||
|
.split(',');
|
||||||
|
|
||||||
|
let parse_error = || AtError::ParseAddressError(string.to_string());
|
||||||
|
|
||||||
|
if !ADDR_REGEX.is_match(string) {
|
||||||
|
return Err(parse_error());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
host: items.next().ok_or_else(parse_error)?.trim().to_string(),
|
||||||
|
port: items.next().ok_or_else(parse_error)?.trim().parse()?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for Vec<Address> {
|
||||||
|
fn parse(string: &str) -> Result<Self, AtError> {
|
||||||
|
let parse_error = || AtError::ParseAddressError(string.to_string());
|
||||||
|
|
||||||
|
if !ADDR_LIST_REGEX.is_match(string) {
|
||||||
|
return Err(parse_error());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut addrs = vec![];
|
||||||
|
|
||||||
|
for list_caps in ADDR_LIST_REGEX.captures_iter(string) {
|
||||||
|
let elements = &list_caps["elements"].trim();
|
||||||
|
for elt_caps in ADDR_REGEX.captures_iter(elements) {
|
||||||
|
addrs.push(Address {
|
||||||
|
host: elt_caps["host"].to_string(),
|
||||||
|
port: elt_caps["port"].parse()?,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(addrs)
|
||||||
|
}
|
||||||
|
}
|
59
actix-settings/src/actix/backlog.rs
Normal file
59
actix-settings/src/actix/backlog.rs
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
use serde::de;
|
||||||
|
|
||||||
|
use crate::{core::Parse, error::AtError};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub enum Backlog {
|
||||||
|
Default,
|
||||||
|
Manual(usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for Backlog {
|
||||||
|
fn parse(string: &str) -> std::result::Result<Self, AtError> {
|
||||||
|
match string {
|
||||||
|
"default" => Ok(Backlog::Default),
|
||||||
|
string => match string.parse::<usize>() {
|
||||||
|
Ok(val) => Ok(Backlog::Manual(val)),
|
||||||
|
Err(_) => Err(InvalidValue! {
|
||||||
|
expected: "an integer > 0",
|
||||||
|
got: string,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> de::Deserialize<'de> for Backlog {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: de::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
struct BacklogVisitor;
|
||||||
|
|
||||||
|
impl<'de> de::Visitor<'de> for BacklogVisitor {
|
||||||
|
type Value = Backlog;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
let msg = "Either \"default\" or a string containing an integer > 0";
|
||||||
|
formatter.write_str(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: de::Error,
|
||||||
|
{
|
||||||
|
match Backlog::parse(value) {
|
||||||
|
Ok(backlog) => Ok(backlog),
|
||||||
|
Err(AtError::InvalidValue { expected, got, .. }) => Err(
|
||||||
|
de::Error::invalid_value(de::Unexpected::Str(&got), &expected),
|
||||||
|
),
|
||||||
|
Err(_) => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializer.deserialize_string(BacklogVisitor)
|
||||||
|
}
|
||||||
|
}
|
82
actix-settings/src/actix/keep_alive.rs
Normal file
82
actix-settings/src/actix/keep_alive.rs
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
|
use regex::Regex;
|
||||||
|
use serde::{de, Deserialize};
|
||||||
|
|
||||||
|
use crate::{core::Parse, error::AtError};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub enum KeepAlive {
|
||||||
|
Default,
|
||||||
|
Disabled,
|
||||||
|
Os,
|
||||||
|
Seconds(usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for KeepAlive {
|
||||||
|
fn parse(string: &str) -> std::result::Result<Self, AtError> {
|
||||||
|
pub(crate) static FMT: Lazy<Regex> =
|
||||||
|
Lazy::new(|| Regex::new(r"^\d+ seconds$").expect("Failed to compile regex: FMT"));
|
||||||
|
|
||||||
|
pub(crate) static DIGITS: Lazy<Regex> =
|
||||||
|
Lazy::new(|| Regex::new(r"^\d+").expect("Failed to compile regex: FMT"));
|
||||||
|
|
||||||
|
macro_rules! invalid_value {
|
||||||
|
($got:expr) => {
|
||||||
|
Err(InvalidValue! {
|
||||||
|
expected: "a string of the format \"N seconds\" where N is an integer > 0",
|
||||||
|
got: $got,
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let digits_in = |m: regex::Match| &string[m.start()..m.end()];
|
||||||
|
match string {
|
||||||
|
"default" => Ok(KeepAlive::Default),
|
||||||
|
"disabled" => Ok(KeepAlive::Disabled),
|
||||||
|
"OS" | "os" => Ok(KeepAlive::Os),
|
||||||
|
string if !FMT.is_match(string) => invalid_value!(string),
|
||||||
|
string => match DIGITS.find(string) {
|
||||||
|
None => invalid_value!(string),
|
||||||
|
Some(mat) => match digits_in(mat).parse() {
|
||||||
|
Ok(val) => Ok(KeepAlive::Seconds(val)),
|
||||||
|
Err(_) => invalid_value!(string),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> serde::Deserialize<'de> for KeepAlive {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
struct KeepAliveVisitor;
|
||||||
|
|
||||||
|
impl<'de> de::Visitor<'de> for KeepAliveVisitor {
|
||||||
|
type Value = KeepAlive;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
let msg = "Either \"default\", \"disabled\", \"os\", or a string of the format \"N seconds\" where N is an integer > 0";
|
||||||
|
formatter.write_str(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: de::Error,
|
||||||
|
{
|
||||||
|
match KeepAlive::parse(value) {
|
||||||
|
Ok(keep_alive) => Ok(keep_alive),
|
||||||
|
Err(AtError::InvalidValue { expected, got, .. }) => Err(
|
||||||
|
de::Error::invalid_value(de::Unexpected::Str(&got), &expected),
|
||||||
|
),
|
||||||
|
Err(_) => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializer.deserialize_string(KeepAliveVisitor)
|
||||||
|
}
|
||||||
|
}
|
59
actix-settings/src/actix/max_connection_rate.rs
Normal file
59
actix-settings/src/actix/max_connection_rate.rs
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
use serde::{de, Deserialize};
|
||||||
|
|
||||||
|
use crate::{core::Parse, error::AtError};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub enum MaxConnectionRate {
|
||||||
|
Default,
|
||||||
|
Manual(usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for MaxConnectionRate {
|
||||||
|
fn parse(string: &str) -> std::result::Result<Self, AtError> {
|
||||||
|
match string {
|
||||||
|
"default" => Ok(MaxConnectionRate::Default),
|
||||||
|
string => match string.parse::<usize>() {
|
||||||
|
Ok(val) => Ok(MaxConnectionRate::Manual(val)),
|
||||||
|
Err(_) => Err(InvalidValue! {
|
||||||
|
expected: "an integer > 0",
|
||||||
|
got: string,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> serde::Deserialize<'de> for MaxConnectionRate {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
struct MaxConnectionRateVisitor;
|
||||||
|
|
||||||
|
impl<'de> de::Visitor<'de> for MaxConnectionRateVisitor {
|
||||||
|
type Value = MaxConnectionRate;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
let msg = "Either \"default\" or a string containing an integer > 0";
|
||||||
|
formatter.write_str(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: de::Error,
|
||||||
|
{
|
||||||
|
match MaxConnectionRate::parse(value) {
|
||||||
|
Ok(max_connection_rate) => Ok(max_connection_rate),
|
||||||
|
Err(AtError::InvalidValue { expected, got, .. }) => Err(
|
||||||
|
de::Error::invalid_value(de::Unexpected::Str(&got), &expected),
|
||||||
|
),
|
||||||
|
Err(_) => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializer.deserialize_string(MaxConnectionRateVisitor)
|
||||||
|
}
|
||||||
|
}
|
59
actix-settings/src/actix/max_connections.rs
Normal file
59
actix-settings/src/actix/max_connections.rs
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
use serde::{de, Deserialize};
|
||||||
|
|
||||||
|
use crate::{core::Parse, error::AtError};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub enum MaxConnections {
|
||||||
|
Default,
|
||||||
|
Manual(usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for MaxConnections {
|
||||||
|
fn parse(string: &str) -> std::result::Result<Self, AtError> {
|
||||||
|
match string {
|
||||||
|
"default" => Ok(MaxConnections::Default),
|
||||||
|
string => match string.parse::<usize>() {
|
||||||
|
Ok(val) => Ok(MaxConnections::Manual(val)),
|
||||||
|
Err(_) => Err(InvalidValue! {
|
||||||
|
expected: "an integer > 0",
|
||||||
|
got: string,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> serde::Deserialize<'de> for MaxConnections {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
struct MaxConnectionsVisitor;
|
||||||
|
|
||||||
|
impl<'de> de::Visitor<'de> for MaxConnectionsVisitor {
|
||||||
|
type Value = MaxConnections;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
let msg = "Either \"default\" or a string containing an integer > 0";
|
||||||
|
formatter.write_str(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: de::Error,
|
||||||
|
{
|
||||||
|
match MaxConnections::parse(value) {
|
||||||
|
Ok(max_connections) => Ok(max_connections),
|
||||||
|
Err(AtError::InvalidValue { expected, got, .. }) => Err(
|
||||||
|
de::Error::invalid_value(de::Unexpected::Str(&got), &expected),
|
||||||
|
),
|
||||||
|
Err(_) => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializer.deserialize_string(MaxConnectionsVisitor)
|
||||||
|
}
|
||||||
|
}
|
25
actix-settings/src/actix/mode.rs
Normal file
25
actix-settings/src/actix/mode.rs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
use crate::{core::Parse, error::AtError};
|
||||||
|
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize)]
|
||||||
|
pub enum Mode {
|
||||||
|
#[serde(rename = "development")]
|
||||||
|
Development,
|
||||||
|
|
||||||
|
#[serde(rename = "production")]
|
||||||
|
Production,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for Mode {
|
||||||
|
fn parse(string: &str) -> std::result::Result<Self, AtError> {
|
||||||
|
match string {
|
||||||
|
"development" => Ok(Self::Development),
|
||||||
|
"production" => Ok(Self::Production),
|
||||||
|
_ => Err(InvalidValue! {
|
||||||
|
expected: "\"development\" | \"production\".",
|
||||||
|
got: string,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
59
actix-settings/src/actix/num_workers.rs
Normal file
59
actix-settings/src/actix/num_workers.rs
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
use serde::de;
|
||||||
|
|
||||||
|
use crate::{core::Parse, error::AtError};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub enum NumWorkers {
|
||||||
|
Default,
|
||||||
|
Manual(usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for NumWorkers {
|
||||||
|
fn parse(string: &str) -> std::result::Result<Self, AtError> {
|
||||||
|
match string {
|
||||||
|
"default" => Ok(NumWorkers::Default),
|
||||||
|
string => match string.parse::<usize>() {
|
||||||
|
Ok(val) => Ok(NumWorkers::Manual(val)),
|
||||||
|
Err(_) => Err(InvalidValue! {
|
||||||
|
expected: "a positive integer",
|
||||||
|
got: string,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> de::Deserialize<'de> for NumWorkers {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: de::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
struct NumWorkersVisitor;
|
||||||
|
|
||||||
|
impl<'de> de::Visitor<'de> for NumWorkersVisitor {
|
||||||
|
type Value = NumWorkers;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
let msg = "Either \"default\" or a string containing an integer > 0";
|
||||||
|
formatter.write_str(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: de::Error,
|
||||||
|
{
|
||||||
|
match NumWorkers::parse(value) {
|
||||||
|
Ok(num_workers) => Ok(num_workers),
|
||||||
|
Err(AtError::InvalidValue { expected, got, .. }) => Err(
|
||||||
|
de::Error::invalid_value(de::Unexpected::Str(&got), &expected),
|
||||||
|
),
|
||||||
|
Err(_) => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializer.deserialize_string(NumWorkersVisitor)
|
||||||
|
}
|
||||||
|
}
|
88
actix-settings/src/actix/timeout.rs
Normal file
88
actix-settings/src/actix/timeout.rs
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
|
use regex::Regex;
|
||||||
|
use serde::de;
|
||||||
|
|
||||||
|
use crate::{core::Parse, error::AtError};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub enum Timeout {
|
||||||
|
Default,
|
||||||
|
Milliseconds(usize),
|
||||||
|
Seconds(usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for Timeout {
|
||||||
|
fn parse(string: &str) -> std::result::Result<Self, AtError> {
|
||||||
|
pub static FMT: Lazy<Regex> = Lazy::new(|| {
|
||||||
|
Regex::new(r"^\d+ (milliseconds|seconds)$").expect("Failed to compile regex: FMT")
|
||||||
|
});
|
||||||
|
|
||||||
|
pub static DIGITS: Lazy<Regex> =
|
||||||
|
Lazy::new(|| Regex::new(r"^\d+").expect("Failed to compile regex: DIGITS"));
|
||||||
|
|
||||||
|
pub static UNIT: Lazy<Regex> = Lazy::new(|| {
|
||||||
|
Regex::new(r"(milliseconds|seconds)$").expect("Failed to compile regex: UNIT")
|
||||||
|
});
|
||||||
|
|
||||||
|
macro_rules! invalid_value {
|
||||||
|
($got:expr) => {
|
||||||
|
Err(InvalidValue! {
|
||||||
|
expected: "a string of the format \"N seconds\" or \"N milliseconds\" where N is an integer > 0",
|
||||||
|
got: $got,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
match string {
|
||||||
|
"default" => Ok(Timeout::Default),
|
||||||
|
string if !FMT.is_match(string) => invalid_value!(string),
|
||||||
|
string => match (DIGITS.find(string), UNIT.find(string)) {
|
||||||
|
(None, _) => invalid_value!(string),
|
||||||
|
(_, None) => invalid_value!(string),
|
||||||
|
(Some(dmatch), Some(umatch)) => {
|
||||||
|
let digits = &string[dmatch.start()..dmatch.end()];
|
||||||
|
let unit = &string[umatch.start()..umatch.end()];
|
||||||
|
match (digits.parse(), unit) {
|
||||||
|
(Ok(v), "milliseconds") => Ok(Timeout::Milliseconds(v)),
|
||||||
|
(Ok(v), "seconds") => Ok(Timeout::Seconds(v)),
|
||||||
|
_ => invalid_value!(string),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> serde::Deserialize<'de> for Timeout {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
struct TimeoutVisitor;
|
||||||
|
|
||||||
|
impl<'de> de::Visitor<'de> for TimeoutVisitor {
|
||||||
|
type Value = Timeout;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
let msg = "Either \"default\", \"disabled\", \"os\", or a string of the format \"N seconds\" where N is an integer > 0";
|
||||||
|
formatter.write_str(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: de::Error,
|
||||||
|
{
|
||||||
|
match Timeout::parse(value) {
|
||||||
|
Ok(num_workers) => Ok(num_workers),
|
||||||
|
Err(AtError::InvalidValue { expected, got, .. }) => Err(
|
||||||
|
de::Error::invalid_value(de::Unexpected::Str(&got), &expected),
|
||||||
|
),
|
||||||
|
Err(_) => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializer.deserialize_string(TimeoutVisitor)
|
||||||
|
}
|
||||||
|
}
|
11
actix-settings/src/actix/tls.rs
Normal file
11
actix-settings/src/actix/tls.rs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize)]
|
||||||
|
#[serde(rename_all = "kebab-case")]
|
||||||
|
pub struct Tls {
|
||||||
|
pub enabled: bool,
|
||||||
|
pub certificate: PathBuf,
|
||||||
|
pub private_key: PathBuf,
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
/// A library to process Server.toml files
|
//! Easily manage Actix Web's settings from a TOML file and environment variables.
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
env, fmt,
|
env, fmt,
|
||||||
fs::File,
|
fs::File,
|
||||||
@ -22,7 +23,10 @@ mod error;
|
|||||||
mod actix;
|
mod actix;
|
||||||
mod core;
|
mod core;
|
||||||
|
|
||||||
pub use self::actix::*;
|
pub use self::actix::{
|
||||||
|
ActixSettings, Address, Backlog, KeepAlive, MaxConnectionRate, MaxConnections, Mode,
|
||||||
|
NumWorkers, Timeout, Tls,
|
||||||
|
};
|
||||||
pub use self::core::Parse;
|
pub use self::core::Parse;
|
||||||
pub use self::error::{AtError, AtResult};
|
pub use self::error::{AtError, AtResult};
|
||||||
|
|
||||||
@ -214,15 +218,11 @@ where
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
#![allow(non_snake_case)]
|
use super::*;
|
||||||
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use actix_web::{App, HttpServer};
|
use actix_web::{App, HttpServer};
|
||||||
use serde::Deserialize;
|
|
||||||
|
|
||||||
use crate::actix::*; // used for value construction in assertions
|
|
||||||
use crate::{ApplySettings, AtResult, BasicSettings, Settings};
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn apply_settings() -> AtResult<()> {
|
fn apply_settings() -> AtResult<()> {
|
||||||
@ -657,12 +657,12 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn override_extended_field_with_custom_type() -> AtResult<()> {
|
fn override_extended_field_with_custom_type() -> AtResult<()> {
|
||||||
#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
|
||||||
struct NestedSetting {
|
struct NestedSetting {
|
||||||
foo: String,
|
foo: String,
|
||||||
bar: bool,
|
bar: bool,
|
||||||
}
|
}
|
||||||
#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
|
||||||
struct AppSettings {
|
struct AppSettings {
|
||||||
#[serde(rename = "example-name")]
|
#[serde(rename = "example-name")]
|
||||||
example_name: String,
|
example_name: String,
|
||||||
|
Loading…
Reference in New Issue
Block a user