diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/atom/mod.rs | 154 | ||||
-rw-r--r-- | src/atom/urn.rs | 49 | ||||
-rwxr-xr-x[-rw-r--r--] | src/atomizer.rs | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | src/error.rs | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | src/fs.rs | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | src/ifc.rs | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | src/main.rs | 12 | ||||
-rwxr-xr-x[-rw-r--r--] | src/markup.rs | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | src/settings.rs | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | src/templated.rs | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | src/timeparse.rs | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | src/util.rs | 0 |
12 files changed, 209 insertions, 6 deletions
diff --git a/src/atom/mod.rs b/src/atom/mod.rs new file mode 100644 index 0000000..2020163 --- /dev/null +++ b/src/atom/mod.rs @@ -0,0 +1,154 @@ +mod urn; + +use std::str::FromStr; + +use bempline::{variables, Document, Options}; +use camino::{Utf8Path, Utf8PathBuf}; +use confindent::{let_get, Confindent, Entry, Node}; +use time::{format_description::well_known, OffsetDateTime}; +use urn::Urn; + +use crate::{markup, templated::Templated, timeparse}; + +pub fn main() -> ! { + let awake_conf = Confindent::from_file(std::env::args().nth(2).unwrap()).unwrap(); + + let root: Utf8PathBuf = awake_conf.child_parse("Webroot").unwrap(); + + // Grab the atom config and then grab the atom template + let atom_conf_path = std::env::args().nth(3).unwrap_or(String::from("atom.conf")); + let mut atom_conf = Confindent::from_file(&atom_conf_path).unwrap(); + let atom = Document::from_file( + root.clone() + .join(atom_conf.child_value("Template").unwrap()) + .canonicalize_utf8() + .unwrap(), + Options::default(), + ) + .unwrap(); + + let mut changed = false; + // Go through every feed and create the entries + let feeds = atom_conf.children_mut("Feed"); + for feed in feeds { + make_feed(feed, &mut changed, &root, atom.clone()) + } + + // If the atom has changed, probably because we created an ID + // write it to disk. + if changed { + std::fs::write(atom_conf_path, atom_conf.to_string()); + } + + std::process::exit(0); +} + +pub struct AtomFeed { + /// Where is the atom located in the webroot. (relative to webroot) + relpath: Utf8PathBuf, + /// What unique ID does this Feed have? + id: String, + + title: String, + subtitle: String, + updated: OffsetDateTime, + author_name: String, + author_email: String, + + entries: Vec<AtomEntry>, +} + +pub struct AtomEntry { + /// What file does this entry direct to? This file will be opened to inspect + /// the frontmatter for information to fill out the entry with. It will also + /// be used to create the link to the entry. + relpath: Utf8PathBuf, + /// What unique ID does this Entry have? + id: String, + + title: String, + published: OffsetDateTime, + updated: OffsetDateTime, +} + +/// Parses all the options of a feed and generates the build job +pub fn make_feed(feed: &mut Entry, changed: &mut bool, root: &Utf8Path, mut atom: Document) { + let_get!( + feed, + relpath: Utf8PathBuf = "Output", + clone id = "Id", + clone title = "Title", + clone subtitle = "Subtitle", + clone updated = "Updated", + ); + + //FIXME: gen- We need to backresolve the feed URL + let feed_link = ""; + let author_name = feed.get("Author/Name").unwrap().to_owned(); + let author_email = feed.get("Author/Email").unwrap().to_owned(); + + let mut atomfeed = AtomFeed { + relpath, + id, + title, + subtitle, + updated: timeparse::parse(&updated).unwrap(), + author_name, + author_email, + entries: vec![], + }; + + let entries = feed.children_mut("Entry"); + for entry in entries { + if !entry.has_child("Id") { + //TODO: gen- Read NID from conf? + let id = Urn::new_random("dreamy"); + entry.push_entry(("Id", id)); + *changed = true; + } + + atomfeed.entries.push(make_entry(entry, &root)); + } +} + +fn make_entry<P: AsRef<Utf8Path>>(entry: &Entry, webroot: P) -> AtomEntry { + let relpath: Utf8PathBuf = entry.parse().unwrap(); + let path = webroot.as_ref().join(&relpath); + + let entry_content = match std::fs::read_to_string(&path) { + Ok(ok) => ok, + Err(e) => { + panic!("failed to get file at {path}: {e}"); + } + }; + let entry_templated = Templated::from_str(&entry_content).unwrap(); + + let conf_or_frontmatter = |conf_key: &str, front_key: &str| -> &str { + entry + .child_value(conf_key) + .unwrap_or_else(|| entry_templated.frontmatter.get(front_key).unwrap()) + }; + + let title = conf_or_frontmatter("Title", "title").to_owned(); + let id = entry.child_value("Id").unwrap().to_owned(); + + let entry_published_raw = conf_or_frontmatter("Published", "published"); + + let updated = timeparse::parse(entry.child_value("Updated").unwrap_or_else(|| { + entry_templated + .frontmatter + .get("updated") + .unwrap_or(entry_published_raw) + })) + .unwrap(); + + let published = timeparse::parse(entry_published_raw).unwrap(); + + AtomEntry { + relpath, + id, + title, + published, + updated, + } +} diff --git a/src/atom/urn.rs b/src/atom/urn.rs new file mode 100644 index 0000000..9ec73ae --- /dev/null +++ b/src/atom/urn.rs @@ -0,0 +1,49 @@ +use core::fmt; + +use rand::{rngs::OsRng, Rng}; + +//TODO: gen- Check URN are valid +// https://www.rfc-editor.org/rfc/rfc2141#section-2.1 +pub struct Urn { + /// Namespace Identifier + nid: String, + /// Namespace Specific string. This is the unique part of the identifier + nss: String, +} + +impl Urn { + /// awake specific function for generating a URN in the form of: + /// `urn:NID:1234-5678` + /// Where 1234-5678 is a randomly generated eight digit ID broken in two. + pub fn new_random<S: Into<String>>(nid: S) -> Self { + let first = random_base58(4); + let second = random_base58(4); + + Self { + nid: nid.into(), + nss: format!("{first}-{second}"), + } + } +} + +impl fmt::Display for Urn { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let Urn { nid, nss } = self; + + write!(f, "urn:{nid}:{nss}") + } +} + +const BASE58: &'static [u8] = b"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; +const USER_ID_LENGTH: usize = 6; +const SESSION_ID_LENGTH: usize = 12; + +/// Random Base58 string, `count` characters long, using OsRng which is assumed +/// to be secure +/// > assumed that system always provides high-quality cryptographically secure random data +fn random_base58(count: usize) -> String { + let mut rng = OsRng::default(); + std::iter::from_fn(|| Some(BASE58[rng.gen_range(0..BASE58.len())] as char)) + .take(count) + .collect() +} diff --git a/src/atomizer.rs b/src/atomizer.rs index e6a147b..e6a147b 100644..100755 --- a/src/atomizer.rs +++ b/src/atomizer.rs diff --git a/src/error.rs b/src/error.rs index 56539d0..56539d0 100644..100755 --- a/src/error.rs +++ b/src/error.rs diff --git a/src/fs.rs b/src/fs.rs index 831aa86..831aa86 100644..100755 --- a/src/fs.rs +++ b/src/fs.rs diff --git a/src/ifc.rs b/src/ifc.rs index d0a9f5f..d0a9f5f 100644..100755 --- a/src/ifc.rs +++ b/src/ifc.rs diff --git a/src/main.rs b/src/main.rs index 0c61389..5784588 100644..100755 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,4 @@ -mod atomizer; +mod atom; mod error; mod fs; mod ifc; @@ -20,7 +20,7 @@ use axum::{ }; use bempline::{variables, Document, Options}; use camino::Utf8PathBuf; -use confindent::Confindent; +use confindent::{Confindent, Node}; pub use error::RuntimeError; use fs::Filesystem; use settings::Settings; @@ -36,7 +36,7 @@ use crate::{ #[tokio::main] async fn main() { match std::env::args().nth(1).as_deref() { - Some("atomizer") => atomizer::main(), + Some("atomizer") => atom::main(), /* fallthrough*/ Some("serve") => (), _ => (), @@ -250,7 +250,7 @@ async fn send_template( for style in templated.frontmatter.get_many("style") { let mut pat = style_pattern.clone(); pat.set("style", style); - template.set_pattern("styles", pat); + template.set_pattern(pat); } // path to the file for navigation @@ -285,7 +285,7 @@ async fn send_template( let mut pat = path_pattern.clone(); pat.set("path_link", "/"); pat.set("path_name", "home"); - template.set_pattern("path", pat); + template.set_pattern(pat); for part in path { link.push(part); @@ -293,7 +293,7 @@ async fn send_template( let mut pat = path_pattern.clone(); pat.set("path_link", &link); pat.set("path_name", part); - template.set_pattern("path", pat); + template.set_pattern(pat); } } diff --git a/src/markup.rs b/src/markup.rs index a1516f4..a1516f4 100644..100755 --- a/src/markup.rs +++ b/src/markup.rs diff --git a/src/settings.rs b/src/settings.rs index 06abc18..06abc18 100644..100755 --- a/src/settings.rs +++ b/src/settings.rs diff --git a/src/templated.rs b/src/templated.rs index c6daac8..c6daac8 100644..100755 --- a/src/templated.rs +++ b/src/templated.rs diff --git a/src/timeparse.rs b/src/timeparse.rs index f4eaca5..f4eaca5 100644..100755 --- a/src/timeparse.rs +++ b/src/timeparse.rs diff --git a/src/util.rs b/src/util.rs index a3cc064..a3cc064 100644..100755 --- a/src/util.rs +++ b/src/util.rs |