Skip to content
This repository has been archived by the owner on Sep 10, 2024. It is now read-only.

Commit

Permalink
Simplify ConfigurationSection trait & skip default values when serial…
Browse files Browse the repository at this point in the history
…izing

This removes the `test` and `generate` methods from the
`ConfigurationSection` trait, as they did not really had a reason to
exist in the trait itself.
  • Loading branch information
sandhose committed Mar 22, 2024
1 parent fc7489c commit 8e7bb26
Show file tree
Hide file tree
Showing 18 changed files with 306 additions and 404 deletions.
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion crates/config/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ workspace = true
[dependencies]
tokio = { version = "1.36.0", features = ["fs", "rt"] }
tracing.workspace = true
async-trait.workspace = true

thiserror.workspace = true
anyhow.workspace = true
Expand Down
30 changes: 16 additions & 14 deletions crates/config/src/sections/branding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use async_trait::async_trait;
use rand::Rng;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use url::Url;
Expand All @@ -24,38 +22,42 @@ use crate::ConfigurationSection;
#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize, Default)]
pub struct BrandingConfig {
/// A human-readable name. Defaults to the server's address.
#[serde(skip_serializing_if = "Option::is_none")]
pub service_name: Option<String>,

/// Link to a privacy policy, displayed in the footer of web pages and
/// emails. It is also advertised to clients through the `op_policy_uri`
/// OIDC provider metadata.
#[serde(skip_serializing_if = "Option::is_none")]
pub policy_uri: Option<Url>,

/// Link to a terms of service document, displayed in the footer of web
/// pages and emails. It is also advertised to clients through the
/// `op_tos_uri` OIDC provider metadata.
#[serde(skip_serializing_if = "Option::is_none")]
pub tos_uri: Option<Url>,

/// Legal imprint, displayed in the footer in the footer of web pages and
/// emails.
#[serde(skip_serializing_if = "Option::is_none")]
pub imprint: Option<String>,

/// Logo displayed in some web pages.
#[serde(skip_serializing_if = "Option::is_none")]
pub logo_uri: Option<Url>,
}

#[async_trait]
impl ConfigurationSection for BrandingConfig {
const PATH: Option<&'static str> = Some("branding");

async fn generate<R>(_rng: R) -> anyhow::Result<Self>
where
R: Rng + Send,
{
Ok(Self::default())
impl BrandingConfig {
/// Returns true if the configuration is the default one
pub(crate) fn is_default(&self) -> bool {
self.service_name.is_none()
&& self.policy_uri.is_none()
&& self.tos_uri.is_none()
&& self.imprint.is_none()
&& self.logo_uri.is_none()
}
}

fn test() -> Self {
Self::default()
}
impl ConfigurationSection for BrandingConfig {
const PATH: Option<&'static str> = Some("branding");
}
21 changes: 7 additions & 14 deletions crates/config/src/sections/clients.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,9 @@

use std::ops::Deref;

use async_trait::async_trait;
use figment::Figment;
use mas_iana::oauth::OAuthClientAuthenticationMethod;
use mas_jose::jwk::PublicJsonWebKeySet;
use rand::Rng;
use schemars::JsonSchema;
use serde::{de::Error, Deserialize, Serialize};
use ulid::Ulid;
Expand Down Expand Up @@ -211,6 +209,13 @@ impl ClientConfig {
#[serde(transparent)]
pub struct ClientsConfig(#[schemars(with = "Vec::<ClientConfig>")] Vec<ClientConfig>);

impl ClientsConfig {
/// Returns true if all fields are at their default values
pub(crate) fn is_default(&self) -> bool {
self.0.is_empty()
}
}

impl Deref for ClientsConfig {
type Target = Vec<ClientConfig>;

Expand All @@ -228,17 +233,9 @@ impl IntoIterator for ClientsConfig {
}
}

#[async_trait]
impl ConfigurationSection for ClientsConfig {
const PATH: Option<&'static str> = Some("clients");

async fn generate<R>(_rng: R) -> anyhow::Result<Self>
where
R: Rng + Send,
{
Ok(Self::default())
}

fn validate(&self, figment: &Figment) -> Result<(), figment::error::Error> {
for (index, client) in self.0.iter().enumerate() {
client.validate().map_err(|mut err| {
Expand All @@ -253,10 +250,6 @@ impl ConfigurationSection for ClientsConfig {

Ok(())
}

fn test() -> Self {
Self::default()
}
}

#[cfg(test)]
Expand Down
14 changes: 0 additions & 14 deletions crates/config/src/sections/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@

use std::{num::NonZeroU32, time::Duration};

use async_trait::async_trait;
use camino::Utf8PathBuf;
use rand::Rng;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use serde_with::serde_as;
Expand Down Expand Up @@ -150,17 +148,9 @@ pub struct DatabaseConfig {
pub max_lifetime: Option<Duration>,
}

#[async_trait]
impl ConfigurationSection for DatabaseConfig {
const PATH: Option<&'static str> = Some("database");

async fn generate<R>(_rng: R) -> anyhow::Result<Self>
where
R: Rng + Send,
{
Ok(Self::default())
}

fn validate(&self, figment: &figment::Figment) -> Result<(), figment::error::Error> {
let metadata = figment.find_metadata(Self::PATH.unwrap());

Expand All @@ -185,10 +175,6 @@ impl ConfigurationSection for DatabaseConfig {

Ok(())
}

fn test() -> Self {
Self::default()
}
}

#[cfg(test)]
Expand Down
14 changes: 0 additions & 14 deletions crates/config/src/sections/email.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@

use std::num::NonZeroU16;

use async_trait::async_trait;
use rand::Rng;
use schemars::JsonSchema;
use serde::{de::Error, Deserialize, Serialize};

Expand Down Expand Up @@ -181,17 +179,9 @@ impl Default for EmailConfig {
}
}

#[async_trait]
impl ConfigurationSection for EmailConfig {
const PATH: Option<&'static str> = Some("email");

async fn generate<R>(_rng: R) -> anyhow::Result<Self>
where
R: Rng + Send,
{
Ok(Self::default())
}

fn validate(&self, figment: &figment::Figment) -> Result<(), figment::error::Error> {
let metadata = figment.find_metadata(Self::PATH.unwrap());

Expand Down Expand Up @@ -283,8 +273,4 @@ impl ConfigurationSection for EmailConfig {

Ok(())
}

fn test() -> Self {
Self::default()
}
}
34 changes: 18 additions & 16 deletions crates/config/src/sections/experimental.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use async_trait::async_trait;
use chrono::Duration;
use rand::Rng;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use serde_with::serde_as;
Expand All @@ -25,6 +23,10 @@ fn default_token_ttl() -> Duration {
Duration::microseconds(5 * 60 * 1000 * 1000)
}

fn is_default_token_ttl(value: &Duration) -> bool {
*value == default_token_ttl()
}

/// Configuration sections for experimental options
///
/// Do not change these options unless you know what you are doing.
Expand All @@ -33,14 +35,20 @@ fn default_token_ttl() -> Duration {
pub struct ExperimentalConfig {
/// Time-to-live of access tokens in seconds. Defaults to 5 minutes.
#[schemars(with = "u64", range(min = 60, max = 86400))]
#[serde(default = "default_token_ttl")]
#[serde(
default = "default_token_ttl",
skip_serializing_if = "is_default_token_ttl"
)]
#[serde_as(as = "serde_with::DurationSeconds<i64>")]
pub access_token_ttl: Duration,

/// Time-to-live of compatibility access tokens in seconds. Defaults to 5
/// minutes.
#[schemars(with = "u64", range(min = 60, max = 86400))]
#[serde(default = "default_token_ttl")]
#[serde(
default = "default_token_ttl",
skip_serializing_if = "is_default_token_ttl"
)]
#[serde_as(as = "serde_with::DurationSeconds<i64>")]
pub compat_token_ttl: Duration,
}
Expand All @@ -54,18 +62,12 @@ impl Default for ExperimentalConfig {
}
}

#[async_trait]
impl ConfigurationSection for ExperimentalConfig {
const PATH: Option<&'static str> = Some("experimental");

async fn generate<R>(_rng: R) -> anyhow::Result<Self>
where
R: Rng + Send,
{
Ok(Self::default())
impl ExperimentalConfig {
pub(crate) fn is_default(&self) -> bool {
is_default_token_ttl(&self.access_token_ttl) && is_default_token_ttl(&self.compat_token_ttl)
}
}

fn test() -> Self {
Self::default()
}
impl ConfigurationSection for ExperimentalConfig {
const PATH: Option<&'static str> = Some("experimental");
}
24 changes: 9 additions & 15 deletions crates/config/src/sections/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,9 @@
use std::{borrow::Cow, io::Cursor};

use anyhow::bail;
use async_trait::async_trait;
use camino::Utf8PathBuf;
use ipnetwork::IpNetwork;
use mas_keystore::PrivateKey;
use rand::Rng;
use rustls_pki_types::{CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -61,6 +59,10 @@ fn http_listener_assets_path_default() -> Utf8PathBuf {
"./share/assets/".into()
}

fn is_default_http_listener_assets_path(value: &Utf8PathBuf) -> bool {
*value == http_listener_assets_path_default()
}

fn default_trusted_proxies() -> Vec<IpNetwork> {
vec![
IpNetwork::new([192, 128, 0, 0].into(), 16).unwrap(),
Expand Down Expand Up @@ -302,7 +304,10 @@ pub enum Resource {
/// Static files
Assets {
/// Path to the directory to serve.
#[serde(default = "http_listener_assets_path_default")]
#[serde(
default = "http_listener_assets_path_default",
skip_serializing_if = "is_default_http_listener_assets_path"
)]
#[schemars(with = "String")]
path: Utf8PathBuf,
},
Expand Down Expand Up @@ -356,6 +361,7 @@ pub struct HttpConfig {
pub public_base: Url,

/// OIDC issuer URL. Defaults to `public_base` if not set.
#[serde(skip_serializing_if = "Option::is_none")]
pub issuer: Option<Url>,
}

Expand Down Expand Up @@ -401,17 +407,9 @@ impl Default for HttpConfig {
}
}

#[async_trait]
impl ConfigurationSection for HttpConfig {
const PATH: Option<&'static str> = Some("http");

async fn generate<R>(_rng: R) -> anyhow::Result<Self>
where
R: Rng + Send,
{
Ok(Self::default())
}

fn validate(&self, figment: &figment::Figment) -> Result<(), figment::Error> {
for (index, listener) in self.listeners.iter().enumerate() {
let annotate = |mut error: figment::Error| {
Expand Down Expand Up @@ -473,8 +471,4 @@ impl ConfigurationSection for HttpConfig {

Ok(())
}

fn test() -> Self {
Self::default()
}
}
12 changes: 6 additions & 6 deletions crates/config/src/sections/matrix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use async_trait::async_trait;
use rand::{
distributions::{Alphanumeric, DistString},
Rng,
Expand Down Expand Up @@ -48,22 +47,23 @@ pub struct MatrixConfig {
pub endpoint: Url,
}

#[async_trait]
impl ConfigurationSection for MatrixConfig {
const PATH: Option<&'static str> = Some("matrix");
}

async fn generate<R>(mut rng: R) -> anyhow::Result<Self>
impl MatrixConfig {
pub(crate) fn generate<R>(mut rng: R) -> Self
where
R: Rng + Send,
{
Ok(Self {
Self {
homeserver: default_homeserver(),
secret: Alphanumeric.sample_string(&mut rng, 32),
endpoint: default_endpoint(),
})
}
}

fn test() -> Self {
pub(crate) fn test() -> Self {
Self {
homeserver: default_homeserver(),
secret: "test".to_owned(),
Expand Down
Loading

0 comments on commit 8e7bb26

Please sign in to comment.