Work on modularizing - things were getting messy

This commit is contained in:
Daniel Flanagan 2024-05-13 17:53:23 -05:00
parent 7b79205148
commit 1843f9fac3
11 changed files with 177 additions and 105 deletions

11
Cargo.lock generated
View file

@ -757,7 +757,9 @@ dependencies = [
"futures", "futures",
"minijinja", "minijinja",
"notify", "notify",
"pathdiff",
"redact", "redact",
"serde",
"sled", "sled",
"tokio", "tokio",
"tower", "tower",
@ -765,6 +767,7 @@ dependencies = [
"tower-livereload", "tower-livereload",
"tracing", "tracing",
"tracing-subscriber", "tracing-subscriber",
"walkdir",
] ]
[[package]] [[package]]
@ -1232,18 +1235,18 @@ checksum = "d369a96f978623eb3dc28807c4852d6cc617fed53da5d3c400feff1ef34a714a"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.200" version = "1.0.201"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddc6f9cc94d67c0e21aaf7eda3a010fd3af78ebf6e096aa6e2e13c79749cce4f" checksum = "780f1cebed1629e4753a1a38a3c72d30b97ec044f0aef68cb26650a3c5cf363c"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.200" version = "1.0.201"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "856f046b9400cee3c8c94ed572ecdb752444c24528c035cd35882aad6f492bcb" checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",

View file

@ -12,7 +12,9 @@ config = "0.14.0"
futures = "0.3.30" futures = "0.3.30"
minijinja = { version = "2.0.1", features = ["loader"] } minijinja = { version = "2.0.1", features = ["loader"] }
notify = "6.1.1" notify = "6.1.1"
pathdiff = "0.2.1"
redact = { version = "0.1.9", features = ["serde"] } redact = { version = "0.1.9", features = ["serde"] }
serde = "1.0.201"
sled = "0.34.7" sled = "0.34.7"
tokio = { version = "1.37.0", features = ["full"] } tokio = { version = "1.37.0", features = ["full"] }
tower = "0.4.13" tower = "0.4.13"
@ -20,3 +22,4 @@ tower-http = { version = "0.5.2", features = ["fs"] }
tower-livereload = "0.9.2" tower-livereload = "0.9.2"
tracing = "0.1.40" tracing = "0.1.40"
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
walkdir = "2.5.0"

View file

@ -28,6 +28,7 @@
pkg-config pkg-config
inotify-tools inotify-tools
tailwindcss tailwindcss
nodePackages.typescript-language-server
]; ];
}; };

View file

@ -1,7 +0,0 @@
{% extends "page.html.jinja" %}
{% block body %}
<h1>Index</h1>
<p class="important">
Welcome to my awesome homepage.
</p>
{% endblock %}

View file

@ -2,14 +2,11 @@ use axum::extract::State;
use axum::response::IntoResponse; use axum::response::IntoResponse;
use axum::routing::get; use axum::routing::get;
use axum::{http::StatusCode, response::Html, serve, Router}; use axum::{http::StatusCode, response::Html, serve, Router};
use minijinja::{context, Environment}; use minijinja::context;
use notify::{Config, RecommendedWatcher, RecursiveMode, Watcher}; use notify::{Config, RecommendedWatcher, RecursiveMode, Watcher};
use std::process::Stdio;
use std::sync::Arc;
use std::{path::PathBuf, str::FromStr, sync::OnceLock}; use std::{path::PathBuf, str::FromStr, sync::OnceLock};
use tokio::io::{AsyncBufReadExt, BufReader}; use templates::Templates;
use tokio::sync::mpsc::channel; use tokio::sync::mpsc::channel;
use tokio::sync::Mutex;
use tower_http::services::ServeDir; use tower_http::services::ServeDir;
use tower_livereload::{LiveReloadLayer, Reloader}; use tower_livereload::{LiveReloadLayer, Reloader};
pub use tracing::{debug, error, event, info, span, warn, Level}; pub use tracing::{debug, error, event, info, span, warn, Level};
@ -18,19 +15,9 @@ pub use tracing::{debug, error, event, info, span, warn, Level};
struct Berr(Box<dyn std::error::Error>); struct Berr(Box<dyn std::error::Error>);
type Besult<T> = std::result::Result<T, Berr>; type Besult<T> = std::result::Result<T, Berr>;
mod observe { mod observe;
pub fn setup_logging() { mod tailwind;
color_eyre::install().expect("Failed to install color_eyre"); mod templates;
let filter = tracing_subscriber::EnvFilter::builder()
.with_default_directive(<tracing_subscriber::filter::Directive>::from(
tracing::level_filters::LevelFilter::TRACE,
))
.parse_lossy("info,lyrs=trace");
tracing_subscriber::fmt().with_env_filter(filter).init();
}
}
fn static_file_dir() -> &'static PathBuf { fn static_file_dir() -> &'static PathBuf {
static STATIC_FILE_DIR: OnceLock<PathBuf> = OnceLock::new(); static STATIC_FILE_DIR: OnceLock<PathBuf> = OnceLock::new();
@ -39,53 +26,22 @@ fn static_file_dir() -> &'static PathBuf {
#[derive(Clone)] #[derive(Clone)]
struct AppState { struct AppState {
templates: Arc<Mutex<Environment<'static>>>, templates: Templates,
} }
#[tokio::main] #[tokio::main]
async fn main() -> Besult<()> { async fn main() -> Besult<()> {
// load configuration? // load configuration?
observe::setup_logging(); let _setup_logging = observe::setup_logging();
// TODO: reload templates when they change? separate watcher?
let templates = Templates::try_load().await?;
let mut tt = templates.clone();
let templates_watcher = tt.start_watcher();
// TODO: only start tailwind if in dev mode? // TODO: only start tailwind if in dev mode?
tokio::spawn(async move { tokio::spawn(async { tailwind::start_watcher() });
info!("Starting tailwind..."); tokio::spawn(async move { templates_watcher.await });
match tokio::process::Command::new("tailwindcss")
.args(["-i", "src/style.css", "-o", "static/style.css", "--watch"])
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
{
Ok(mut tw) => {
info!("Tailwind spawned!");
let mut stdout_reader = BufReader::new(tw.stdout.take().unwrap()).lines();
tokio::spawn(async move {
while let Ok(Some(l)) = stdout_reader.next_line().await {
if l.trim().len() > 0 {
event!(target: "tailwind::stdout", Level::INFO, "{l}");
}
}
});
let mut stderr_reader = BufReader::new(tw.stderr.take().unwrap()).lines();
tokio::spawn(async move {
while let Ok(Some(l)) = stderr_reader.next_line().await {
if l.trim().len() > 0 {
event!(target: "tailwind::stderr", Level::INFO, "{l}");
}
}
});
}
Err(e) => error!("Failed to spawn Tailwind: {e}"),
}
});
let templates = Arc::new(Mutex::new(Environment::new()));
while let Some(d) = tokio::fs::read_dir("templates").await?.next_entry().await? {
templates.clone().lock().await.add_template_owned(
d.file_name().into_string().unwrap(),
std::fs::read_to_string(d.path())?,
)?;
}
// pulling the watcher into main's scope lets it live until the program dies // pulling the watcher into main's scope lets it live until the program dies
let (rl_layer, _watcher) = live_reload_layer()?; let (rl_layer, _watcher) = live_reload_layer()?;
@ -105,10 +61,8 @@ async fn index(State(state): State<AppState>) -> Besult<Html<String>> {
Ok(Html( Ok(Html(
state state
.templates .templates
.lock() .render("pages/index.html.jinja", context!())
.await .await?,
.get_template("page.html")?
.render(context!())?,
)) ))
} }
@ -142,9 +96,7 @@ fn static_file_watcher(
watcher.watch(static_file_dir(), RecursiveMode::Recursive)?; watcher.watch(static_file_dir(), RecursiveMode::Recursive)?;
tokio::spawn(async move { tokio::spawn(async move {
info!("Recieving...");
while let Some(res) = rx.recv().await { while let Some(res) = rx.recv().await {
info!("Recieved! {res:#?}");
match res { match res {
Ok(event) => { Ok(event) => {
info!("fs event: {event:#?}"); info!("fs event: {event:#?}");

11
src/observe.rs Normal file
View file

@ -0,0 +1,11 @@
pub fn setup_logging() {
color_eyre::install().expect("Failed to install color_eyre");
let filter = tracing_subscriber::EnvFilter::builder()
.with_default_directive(<tracing_subscriber::filter::Directive>::from(
tracing::level_filters::LevelFilter::TRACE,
))
.parse_lossy("info,lyrs=trace");
tracing_subscriber::fmt().with_env_filter(filter).init();
}

37
src/tailwind.rs Normal file
View file

@ -0,0 +1,37 @@
use std::process::Stdio;
use tokio::{
io::{AsyncBufReadExt, BufReader},
process::Command,
};
use tracing::{error, event, info, Level};
pub fn start_watcher() {
info!("Starting tailwind...");
match Command::new("tailwindcss")
.args(["-i", "src/style.css", "-o", "static/style.css", "--watch"])
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
{
Ok(mut tw) => {
info!("Tailwind spawned!");
let mut stdout_reader = BufReader::new(tw.stdout.take().unwrap()).lines();
tokio::spawn(async move {
while let Ok(Some(l)) = stdout_reader.next_line().await {
if l.trim().len() > 0 {
event!(target: "tailwind::stdout", Level::INFO, "{l}");
}
}
});
let mut stderr_reader = BufReader::new(tw.stderr.take().unwrap()).lines();
tokio::spawn(async move {
while let Ok(Some(l)) = stderr_reader.next_line().await {
if l.trim().len() > 0 {
event!(target: "tailwind::stderr", Level::INFO, "{l}");
}
}
});
}
Err(e) => error!("Failed to spawn Tailwind: {e}"),
}
}

68
src/templates.rs Normal file
View file

@ -0,0 +1,68 @@
use std::sync::Arc;
use minijinja::Environment;
use pathdiff::diff_paths;
use tokio::sync::Mutex;
use tracing::info;
#[derive(Clone)]
pub struct Templates {
env: Arc<Mutex<Environment<'static>>>,
}
pub type Error = Box<dyn std::error::Error>;
impl Templates {
pub fn empty() -> Self {
let env = Arc::new(Mutex::new(Environment::new()));
Self { env }
}
pub async fn try_load() -> Result<Self, Error> {
let mut result = Self::empty();
result.load_env().await?;
Ok(result)
}
pub async fn start_watcher(&mut self) {
info!("TODO: Implement template watcher");
}
pub async fn load_env(&mut self) -> Result<(), Error> {
info!("Loading templates...");
for d in walkdir::WalkDir::new("src/templates") {
match d {
Ok(d) => {
if d.file_type().is_dir() {
continue;
}
let filename: String = diff_paths(d.path(), "src/templates")
.unwrap()
.to_string_lossy()
.into_owned();
info!("Loading template {filename:#?} ({d:#?})");
self.env
.clone()
.lock()
.await
.add_template_owned(filename, std::fs::read_to_string(d.path())?)?;
}
Err(_) => todo!(),
}
}
info!("Done loading templates!");
Ok(())
}
pub async fn render<S: serde::ser::Serialize>(
&self,
template_name: &str,
context: S,
) -> Result<String, minijinja::Error> {
self.env
.lock()
.await
.get_template(template_name)?
.render(context)
}
}

View file

@ -0,0 +1,7 @@
{% extends "page.html.jinja" %}
{% block body %}
<h1>Index</h1>
<p class="important">
Welcome to my awesome homepage!
</p>
{% endblock %}

View file

@ -1,8 +1,7 @@
/** @type {import('tailwindcss').Config} */ /** @type {import('tailwindcss').Config} */
module.exports = { module.exports = {
content: ["./src/**/*.rs","./static/**/*.{html,js}"], theme: { content: ["./src/**/*"], theme: {
colors: { colors: {
rosewater: "var(--Rosewater)", rosewater: "var(--Rosewater)",
flamingo: "var(--Flamingo)", flamingo: "var(--Flamingo)",
pink: "var(--Pink)", pink: "var(--Pink)",
@ -29,10 +28,8 @@ module.exports = {
base: "var(--Base)", base: "var(--Base)",
mantle: "var(--Mantle)", mantle: "var(--Mantle)",
crust: "var(--Crust)", crust: "var(--Crust)",
}, },
extend: { extend: {
}, },
}, },
plugins: [], plugins: [],