Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions src/caching/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ impl Code for CachedImage {
}
}

#[derive(Clone)]
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct CachedMetadata {
pub width: u32,
pub height: u32,
Expand All @@ -82,6 +82,8 @@ pub struct CachedMetadata {
pub channels: u32,
pub has_alpha: bool,
pub orientation: u32,
/// Frames or pages the source carries; 1 for a still image.
pub pages: u32,
}

impl Code for CachedMetadata {
Expand All @@ -101,6 +103,7 @@ impl Code for CachedMetadata {
self.channels.encode(writer)?;
self.has_alpha.encode(writer)?;
self.orientation.encode(writer)?;
self.pages.encode(writer)?;
Ok(())
}

Expand All @@ -126,6 +129,7 @@ impl Code for CachedMetadata {
let channels = u32::decode(reader)?;
let has_alpha = bool::decode(reader)?;
let orientation = u32::decode(reader)?;
let pages = u32::decode(reader)?;

Ok(CachedMetadata {
width,
Expand All @@ -136,11 +140,12 @@ impl Code for CachedMetadata {
channels,
has_alpha,
orientation,
pages,
})
}

fn estimated_size(&self) -> usize {
std::mem::size_of::<u32>() * 4
std::mem::size_of::<u32>() * 5
+ std::mem::size_of::<usize>() * 2
+ std::mem::size_of::<bool>()
+ self.format.len()
Expand All @@ -149,6 +154,11 @@ impl Code for CachedMetadata {
}

/// Represents the different cache backends for imgforge value types.
///
/// Every backing store is behind an `Arc`, so cloning is a handle copy rather
/// than a copy of the cache — which is what lets one cache be shared by more
/// than one `AppState`.
#[derive(Clone)]
pub enum TypedCache<T>
where
T: Clone + Code + Send + Sync + 'static,
Expand Down
65 changes: 65 additions & 0 deletions src/config/env_vars.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
//! Reading and validating environment variables.

use super::ConfigError;
use crate::limits::SecurityLimitError;
use std::env;
use std::str::FromStr;

/// Reads a variable, distinguishing "absent" from "present but not Unicode".
///
/// A variable that cannot be decoded is a configuration mistake, not an absent
/// setting, and silently treating it as absent would start the server with the
/// operator's intent quietly discarded.
pub(super) fn optional_var(name: &'static str) -> Result<Option<String>, ConfigError> {
match env::var(name) {
Ok(value) => Ok(Some(value)),
Err(env::VarError::NotPresent) => Ok(None),
Err(source @ env::VarError::NotUnicode(_)) => Err(ConfigError::InvalidUnicode { name, source }),
}
}

/// Reads a boolean setting, accepting the same spellings the URL options do.
pub(super) fn bool_var(name: &'static str, default: bool) -> Result<bool, ConfigError> {
Ok(optional_var(name)?
.map(|value| {
matches!(
value.trim().to_ascii_lowercase().as_str(),
"1" | "t" | "true" | "yes" | "on"
)
})
.unwrap_or(default))
}

/// Reads a setting parsed by `FromStr`, failing the startup on a bad value.
pub(super) fn parsed_var<T>(name: &'static str) -> Result<Option<T>, ConfigError>
where
T: FromStr,
T::Err: std::fmt::Display,
{
let Some(value) = optional_var(name)? else {
return Ok(None);
};
value
.trim()
.parse()
.map(Some)
.map_err(|source: T::Err| ConfigError::InvalidValue {
name,
value: value.clone(),
reason: source.to_string(),
})
}

/// Reads a validated security limit.
pub(super) fn security_limit_var<T>(name: &'static str) -> Result<Option<T>, ConfigError>
where
T: FromStr<Err = SecurityLimitError>,
{
let Some(value) = optional_var(name)? else {
return Ok(None);
};
value
.parse()
.map(Some)
.map_err(|source| ConfigError::InvalidSecurityLimit { name, value, source })
}
Loading