aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFuwn <[email protected]>2026-01-21 15:02:28 +0000
committerFuwn <[email protected]>2026-01-21 15:02:28 +0000
commitd815570db78e4d06283e4b09c2a6b0106ebfa3e0 (patch)
treee5df63cc0e9b92567d103d220e35489e4a5c0e28 /src
parentfix(main): Remove deprecated std::env::set_var use (diff)
downloadseptember-d815570db78e4d06283e4b09c2a6b0106ebfa3e0.tar.xz
september-d815570db78e4d06283e4b09c2a6b0106ebfa3e0.zip
perf: Cache environment variables at startup
Diffstat (limited to 'src')
-rw-r--r--src/environment.rs56
-rw-r--r--src/html.rs43
-rw-r--r--src/main.rs1
-rw-r--r--src/response.rs30
-rw-r--r--src/url.rs11
5 files changed, 85 insertions, 56 deletions
diff --git a/src/environment.rs b/src/environment.rs
new file mode 100644
index 0000000..dd10171
--- /dev/null
+++ b/src/environment.rs
@@ -0,0 +1,56 @@
+use std::sync::LazyLock;
+
+pub static ENVIRONMENT: LazyLock<Environment> =
+ LazyLock::new(Environment::from_environment);
+
+pub struct Environment {
+ pub root: String,
+ pub css_external: Option<String>,
+ pub primary_colour: Option<String>,
+ pub favicon_external: Option<String>,
+ pub mathjax: bool,
+ pub head: Option<String>,
+ pub header: Option<String>,
+ pub plain_text_route: Option<String>,
+ pub condense_links: Vec<String>,
+ pub condense_links_at_headings: Vec<String>,
+ pub proxy_by_default: bool,
+ pub keep_gemini: Option<Vec<String>>,
+ pub embed_images: Option<String>,
+}
+
+impl Environment {
+ fn from_environment() -> Self {
+ Self {
+ root: std::env::var("ROOT").unwrap_or_else(|_| {
+ log::warn!(
+ "could not use ROOT from environment variables, proceeding with \
+ default root: gemini://fuwn.me"
+ );
+ "gemini://fuwn.me".to_string()
+ }),
+ css_external: std::env::var("CSS_EXTERNAL").ok(),
+ primary_colour: std::env::var("PRIMARY_COLOUR").ok(),
+ favicon_external: std::env::var("FAVICON_EXTERNAL").ok(),
+ mathjax: std::env::var("MATHJAX")
+ .map(|v| v.to_lowercase() == "true")
+ .unwrap_or(true),
+ head: std::env::var("HEAD").ok(),
+ header: std::env::var("HEADER").ok(),
+ plain_text_route: std::env::var("PLAIN_TEXT_ROUTE").ok(),
+ condense_links: std::env::var("CONDENSE_LINKS")
+ .map(|s| s.split(',').map(String::from).collect())
+ .unwrap_or_default(),
+ condense_links_at_headings: std::env::var("CONDENSE_LINKS_AT_HEADINGS")
+ .map(|s| s.split(',').map(String::from).collect())
+ .unwrap_or_default(),
+ proxy_by_default: std::env::var("PROXY_BY_DEFAULT")
+ .map(|v| v.to_lowercase() == "true")
+ .unwrap_or(true),
+ keep_gemini: std::env::var("KEEP_GEMINI")
+ .ok()
+ .map(|s| s.split(',').map(String::from).collect()),
+ embed_images: std::env::var("EMBED_IMAGES").ok(),
+ }
+ }
+}
diff --git a/src/html.rs b/src/html.rs
index ae79489..11ad698 100644
--- a/src/html.rs
+++ b/src/html.rs
@@ -1,7 +1,7 @@
use {
- crate::url::matches_pattern,
+ crate::{environment::ENVIRONMENT, url::matches_pattern},
germ::ast::Node,
- std::{env::var, fmt::Write},
+ std::fmt::Write,
url::Url,
};
@@ -47,26 +47,14 @@ pub fn from_gemini(
let mut title = String::new();
let mut previous_link = false;
let mut previous_link_count = 0;
- let condense_links = {
- let links = var("CONDENSE_LINKS").map_or_else(
- |_| vec![],
- |condense_links| {
- condense_links
- .split(',')
- .map(std::string::ToString::to_string)
- .collect()
- },
- );
-
- links.contains(&url.path().to_string()) || links.contains(&"*".to_string())
- };
- let condensible_headings_value =
- var("CONDENSE_LINKS_AT_HEADINGS").unwrap_or_default();
- let condensible_headings = if condensible_headings_value.is_empty() {
- vec![]
- } else {
- condensible_headings_value.split(',').collect::<Vec<_>>()
- };
+ let condense_links =
+ ENVIRONMENT.condense_links.contains(&url.path().to_string())
+ || ENVIRONMENT.condense_links.contains(&"*".to_string());
+ let condensible_headings = ENVIRONMENT
+ .condense_links_at_headings
+ .iter()
+ .map(String::as_str)
+ .collect::<Vec<_>>();
let mut in_condense_links_flag_trap = !condensible_headings.is_empty();
for node in ast {
@@ -154,10 +142,7 @@ pub fn from_gemini(
href = link_from_host_href(url, &href)?;
}
- if var("PROXY_BY_DEFAULT")
- .unwrap_or_else(|_| "true".to_string())
- .to_lowercase()
- == "true"
+ if ENVIRONMENT.proxy_by_default
&& href.contains("gemini://")
&& !surface
{
@@ -190,9 +175,7 @@ pub fn from_gemini(
}
}
- if let Ok(keeps) = var("KEEP_GEMINI") {
- let patterns = keeps.split(',').collect::<Vec<_>>();
-
+ if let Some(patterns) = &ENVIRONMENT.keep_gemini {
if (href.starts_with('/') || !href.contains("://")) && !surface {
let temporary_href = link_from_host_href(url, &href)?;
let should_exclude = patterns
@@ -213,7 +196,7 @@ pub fn from_gemini(
}
}
- if let Ok(embed_images) = var("EMBED_IMAGES") {
+ if let Some(embed_images) = &ENVIRONMENT.embed_images {
if let Some(extension) = std::path::Path::new(&href).extension() {
if extension == "png"
|| extension == "jpg"
diff --git a/src/main.rs b/src/main.rs
index 56402c9..a39e83e 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -10,6 +10,7 @@
#![recursion_limit = "128"]
#![allow(clippy::cast_precision_loss)]
+mod environment;
mod html;
mod response;
mod url;
diff --git a/src/response.rs b/src/response.rs
index 68c1690..5a3f204 100644
--- a/src/response.rs
+++ b/src/response.rs
@@ -1,9 +1,12 @@
pub mod configuration;
use {
- crate::url::{from_path as url_from_path, matches_pattern},
+ crate::{
+ environment::ENVIRONMENT,
+ url::{from_path as url_from_path, matches_pattern},
+ },
actix_web::{Error, HttpResponse},
- std::{env::var, fmt::Write, time::Instant},
+ std::{fmt::Write, time::Instant},
};
const CSS: &str = include_str!("../default.css");
@@ -142,11 +145,8 @@ pub async fn default(
);
}
- if let Ok(css) = var("CSS_EXTERNAL") {
- let stylesheets =
- css.split(',').filter(|s| !s.is_empty()).collect::<Vec<_>>();
-
- for stylesheet in stylesheets {
+ if let Some(css) = &ENVIRONMENT.css_external {
+ for stylesheet in css.split(',').filter(|s| !s.is_empty()) {
let _ = write!(
&mut html_context,
"<link rel=\"stylesheet\" type=\"text/css\" href=\"{stylesheet}\">",
@@ -158,7 +158,7 @@ pub async fn default(
r#"<link rel="stylesheet" href="https://latex.vercel.app/style.css"><style>{CSS}</style>"#
);
- if let Ok(primary) = var("PRIMARY_COLOUR") {
+ if let Some(primary) = &ENVIRONMENT.primary_colour {
let _ = write!(
&mut html_context,
"<style>:root {{ --primary: {primary} }}</style>"
@@ -171,16 +171,14 @@ pub async fn default(
}
}
- if let Ok(favicon) = var("FAVICON_EXTERNAL") {
+ if let Some(favicon) = &ENVIRONMENT.favicon_external {
let _ = write!(
&mut html_context,
"<link rel=\"icon\" type=\"image/x-icon\" href=\"{favicon}\">",
);
}
- if var("MATHJAX").unwrap_or_else(|_| "true".to_string()).to_lowercase()
- == "true"
- {
+ if ENVIRONMENT.mathjax {
html_context.push_str(
r#"<script type="text/javascript" id="MathJax-script" async
src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js">
@@ -188,15 +186,15 @@ pub async fn default(
);
}
- if let Ok(head) = var("HEAD") {
- html_context.push_str(&head);
+ if let Some(head) = &ENVIRONMENT.head {
+ html_context.push_str(head);
}
let _ = write!(&mut html_context, "<title>{gemini_title}</title>");
let _ = write!(&mut html_context, "</head><body>");
if !http_request.path().starts_with("/proxy") {
- if let Ok(header) = var("HEADER") {
+ if let Some(header) = &ENVIRONMENT.header {
let _ = write!(
&mut html_context,
"<big><blockquote>{header}</blockquote></big>"
@@ -260,7 +258,7 @@ pub async fn default(
env!("VERGEN_GIT_SHA").get(0..5).unwrap_or("UNKNOWN"),
);
- if let Ok(plain_texts) = var("PLAIN_TEXT_ROUTE") {
+ if let Some(plain_texts) = &ENVIRONMENT.plain_text_route {
if plain_texts.split(',').any(|r| {
matches_pattern(r, http_request.path())
|| matches_pattern(r, http_request.path().trim_end_matches('/'))
diff --git a/src/url.rs b/src/url.rs
index 56858e6..0c95eb0 100644
--- a/src/url.rs
+++ b/src/url.rs
@@ -42,16 +42,7 @@ pub fn from_path(
} else {
format!(
"{}{}{}",
- {
- std::env::var("ROOT").unwrap_or_else(|_| {
- warn!(
- "could not use ROOT from environment variables, proceeding with \
- default root: gemini://fuwn.me"
- );
-
- "gemini://fuwn.me".to_string()
- })
- },
+ &crate::environment::ENVIRONMENT.root,
path,
if fallback { "/" } else { "" }
)