From 23871d5aadcaa4d01b7c46cb951854572940414d Mon Sep 17 00:00:00 2001 From: metamuffin Date: Thu, 2 Oct 2025 19:14:17 +0200 Subject: Rewrite --- src/blog/atom.rs | 75 ---------- src/blog/helper.rs | 72 ---------- src/blog/mod.rs | 146 ------------------- src/error.rs | 59 -------- src/layout.rs | 104 -------------- src/main.rs | 67 --------- src/pages.rs | 122 ---------------- src/projects/data.rs | 393 --------------------------------------------------- src/projects/mod.rs | 88 ------------ src/source.rs | 80 ----------- src/wellknown.rs | 40 ------ 11 files changed, 1246 deletions(-) delete mode 100644 src/blog/atom.rs delete mode 100644 src/blog/helper.rs delete mode 100644 src/blog/mod.rs delete mode 100644 src/error.rs delete mode 100644 src/layout.rs delete mode 100644 src/main.rs delete mode 100644 src/pages.rs delete mode 100644 src/projects/data.rs delete mode 100644 src/projects/mod.rs delete mode 100644 src/source.rs delete mode 100644 src/wellknown.rs (limited to 'src') diff --git a/src/blog/atom.rs b/src/blog/atom.rs deleted file mode 100644 index a29ffb1..0000000 --- a/src/blog/atom.rs +++ /dev/null @@ -1,75 +0,0 @@ -use super::{ - helper::{get_articles, ArticleMeta}, - rocket_uri_macro_r_blog_article, rocket_uri_macro_r_blog_index, ARTICLE_ROOT, -}; -use crate::{error::MyResult, uri}; -use rocket::get; -use std::{path::PathBuf, str::FromStr}; - -#[get("/blog/feed.atom")] -pub async fn r_blog_atom() -> MyResult { - let entries = get_articles(&PathBuf::from_str(ARTICLE_ROOT).unwrap()) - .await? - .iter() - .map( - |ArticleMeta { - title, - date, - canonical_name, - .. - }| { - let title = horrible_escape_function(title); - let datetime = iso8601::DateTime { - date: date.clone(), - time: iso8601::Time::default(), - }; - let href = uri!(r_blog_article(canonical_name)); - format!( - r#" - - {title} - - tag:metamuffin.org,{date},{canonical_name} - {datetime} - N/A - - metamuffin - metamuffin@disroot.org - - "# - ) - }, - ) - .collect::>(); - - let feed_url = uri!(r_blog_atom()); - let index_url = uri!(r_blog_index()); - let now = chrono::Utc::now().to_rfc3339(); - - Ok(format!( - r#" - - metamuffin's blog - where they post pointless stuff - - - urn:uuid:3cf2b704-3d94-4f1f-b194-42798ab5b47c - {now} - - metamuffin - metamuffin@disroot.org - - {} - - "#, - entries.join("\n") - )) -} - -pub fn horrible_escape_function(text: &str) -> String { - text.replace("&", "&") - .replace("<", "<") - .replace(">", ">") - .replace("'", "’") - .replace("\"", """) -} diff --git a/src/blog/helper.rs b/src/blog/helper.rs deleted file mode 100644 index 35396c0..0000000 --- a/src/blog/helper.rs +++ /dev/null @@ -1,72 +0,0 @@ -use anyhow::{anyhow, Context}; -use futures::future::join_all; -use std::{ - path::{Path, PathBuf}, - process::Stdio, -}; -use tokio::{ - fs::File, - io::{AsyncBufReadExt, BufReader}, - process::Command, -}; - -#[derive(Clone)] -pub struct ArticleMeta { - pub title: String, - pub canonical_name: String, - pub date: iso8601::Date, -} - -pub async fn article_metadata(path: PathBuf) -> anyhow::Result { - let f = File::open(&path).await.context("article not found")?; - let mut f = BufReader::new(f); - let mut buf = String::new(); - f.read_line(&mut buf).await.context("cant read the file")?; // assume the 1st line has the title - Ok(ArticleMeta { - title: String::from(buf[2..].trim()), - canonical_name: path - .file_stem() - .ok_or(anyhow!("no file stem"))? - .to_str() - .ok_or(anyhow!("this file's name is broken"))? - .to_string(), - date: iso8601::date( - &path - .file_name() - .ok_or(anyhow!("file has no name"))? - .to_str() - .ok_or(anyhow!("this file's name is broken"))?[0..10], - ) - .map_err(|e| anyhow!("file date wrong: {e}"))?, - }) -} - -pub async fn get_articles(blog_root: &Path) -> anyhow::Result> { - let mut a = join_all( - std::fs::read_dir(blog_root)? - .map(|e| e.unwrap()) - .map(|e| article_metadata(e.path())), - ) - .await - .into_iter() - .collect::>>()?; - a.sort_by_cached_key(|e| -match e.date { - iso8601::Date::YMD { year, month, day } => day as i32 + month as i32 * 100 + year * 10000, - _ => unreachable!(), - }); - Ok(a) -} - -// TODO use this somewhere -pub async fn file_history(filename: &str) -> String { - String::from_utf8( - Command::new("/usr/bin/git") - .args(&["log", "--follow", "--pretty=tformat:%as %h %s", filename]) - .stdout(Stdio::piped()) - .output() - .await - .unwrap() - .stdout, - ) - .unwrap() -} diff --git a/src/blog/mod.rs b/src/blog/mod.rs deleted file mode 100644 index b3ab5a4..0000000 --- a/src/blog/mod.rs +++ /dev/null @@ -1,146 +0,0 @@ -pub mod atom; -pub mod helper; - -use self::helper::{article_metadata, get_articles}; -use crate::error::MyResult; -use crate::layout::{DynScaffold, Scaffold}; -use crate::uri; -use anyhow::anyhow; -pub use atom::r_blog_atom; -use atom::rocket_uri_macro_r_blog_atom; -use latex2mathml::DisplayStyle; -use markdown::mdast::Node; -use markup::{raw, DynRender}; -use rocket::{get, response::Redirect}; -use std::{path::PathBuf, str::FromStr}; -use syntect::highlighting::ThemeSet; -use syntect::html::highlighted_html_for_string; -use syntect::parsing::SyntaxSet; -use tokio::fs::read_to_string; - -pub const ARTICLE_ROOT: &'static str = "./blog/articles"; -pub const ASSET_ROOT: &'static str = "./blog/assets"; - -#[get("/blog")] -pub fn r_blog() -> Redirect { - Redirect::to(rocket::uri!(r_blog_index())) -} - -#[get("/blog/index")] -pub async fn r_blog_index() -> MyResult> { - // TODO this is a major performance issue here. requires O(n) syscalls to complete - let articles = get_articles(&PathBuf::from_str(ARTICLE_ROOT).unwrap()).await?; - Ok(Scaffold { - title: "blog index".to_string(), - content: markup::new! { - h2 { "The Weblog" } - p { i { "Articles in reverse-chronological order." } } - p { a[href=uri!(r_blog_atom())]{ "Atom feed" } } - ul { - @for a in &articles { - li { - @a.date.to_string() ": " - a[href=uri!(r_blog_article(&a.canonical_name))] { @a.title } - } - } - } - }, - }) -} - -#[get("/blog/")] -pub async fn r_blog_article(name: &str) -> MyResult> { - let apath = PathBuf::from_str(ARTICLE_ROOT) - .unwrap() - .join(PathBuf::new().with_file_name(name).with_extension("md")); - let a = article_metadata(apath.clone()).await?; - let text = read_to_string(apath).await?; - let ast = markdown::to_mdast( - &text, - &markdown::ParseOptions { - constructs: markdown::Constructs { - math_flow: true, - math_text: true, - ..Default::default() - }, - ..Default::default() - }, - ) - .map_err(|e| anyhow!("the server had trouble parsing markdown: {e}"))?; - - Ok(Scaffold { - title: a.title, - content: markup::new! { - @node_to_render(&ast) - p{i{ "Article written by metamuffin, text licenced under CC BY-ND 4.0, non-trivial code blocks under GPL-3.0-only except where indicated otherwise" }} - }, - }) -} - -fn node_to_render<'a>(node: &'a Node) -> DynRender<'a> { - match node { - Node::Text(s) => markup::new!(@s.value), - Node::Paragraph(el) => markup::new!(p { @for e in &el.children { @node_to_render(e) } }), - Node::List(list) => markup::new!(ul { @for e in &list.children { @node_to_render(e) } }), - Node::Root(el) => markup::new!(article { @for e in &el.children { @node_to_render(e) } }), - Node::ListItem(el) => markup::new!(li { @for e in &el.children { @node_to_render(e) } }), - Node::Emphasis(el) => markup::new!(i { @for e in &el.children { @node_to_render(e) } }), - Node::Strong(el) => markup::new!(strong { @for e in &el.children { @node_to_render(e) } }), - Node::Html(html) => markup::new!(@raw(&html.value)), - Node::Link(l) => { - markup::new!(a[href=&l.url, alt=&l.title] { @for e in &l.children { @node_to_render(e) } }) - } - Node::Break(_) => markup::new!(br;), - Node::InlineCode(s) => markup::new!(code { @s.value }), - Node::Delete(_) => markup::new!("todo1"), - Node::FootnoteReference(_) => markup::new!("todo3"), - Node::FootnoteDefinition(_) => markup::new!("todo4"), - Node::Image(_) => markup::new!("todo5"), - Node::ImageReference(_) => markup::new!("todo6"), - Node::LinkReference(_) => markup::new!("todo8"), - Node::Blockquote(_) => markup::new!("todo10"), - Node::Table(_) => markup::new!("todo12"), - Node::ThematicBreak(_) => markup::new!("todo13"), - Node::TableRow(_) => markup::new!("todo14"), - Node::TableCell(_) => markup::new!("todo15"), - Node::Definition(_) => markup::new!("todo16"), - Node::Toml(_) - | Node::Yaml(_) - | Node::MdxjsEsm(_) - | Node::MdxJsxFlowElement(_) - | Node::MdxJsxTextElement(_) - | Node::MdxTextExpression(_) - | Node::MdxFlowExpression(_) => markup::new!("unsupported"), - Node::Heading(h) => { - let inner = markup::new!(@for e in &h.children { @node_to_render(e) }); - match h.depth { - 1 => markup::new!(h2{@inner}), - 2 => markup::new!(h3{@inner}), - 3 => markup::new!(h4{@inner}), - 4 => markup::new!(h5{@inner}), - 5 => markup::new!(h6{@inner}), - 6 => markup::new!(h6{@inner}), - _ => unreachable!(), - } - } - Node::Code(code) => { - let theme = &ThemeSet::load_defaults().themes["base16-ocean.dark"]; - let syntax = &SyntaxSet::load_defaults_newlines(); - let lang = syntax - .find_syntax_by_extension(&code.lang.to_owned().unwrap_or("txt".to_owned())) - .unwrap_or_else(|| syntax.find_syntax_by_extension("txt").unwrap()); - let html = highlighted_html_for_string(&code.value, syntax, lang, theme).unwrap(); - markup::new!(@raw(&html)) - } - Node::Math(s) => { - let mathml = latex2mathml::latex_to_mathml(&s.value, DisplayStyle::Block) - .expect("invalid block math"); - markup::new!(@raw(&mathml)) - } - Node::InlineMath(s) => { - let mathml = latex2mathml::latex_to_mathml(&s.value, DisplayStyle::Inline) - .expect("invalid inline math"); - markup::new!(@raw(&mathml)) - } - } -} diff --git a/src/error.rs b/src/error.rs deleted file mode 100644 index b6fb84e..0000000 --- a/src/error.rs +++ /dev/null @@ -1,59 +0,0 @@ -use std::fmt::Display; - -use crate::layout::{DynScaffold, Scaffold}; -use rocket::{ - catch, - http::Status, - response::{self, Responder}, - Request, -}; - -#[catch(default)] -pub fn r_catch<'a>(status: Status, _request: &Request) -> DynScaffold<'a> { - Scaffold { - title: "Error".to_string(), - content: markup::new! { - h2 { "Error" } - p { @format!("{status}") } - }, - } -} - -pub type MyResult = Result; - -#[derive(Debug)] -pub struct MyError(pub anyhow::Error); - -impl<'r> Responder<'r, 'static> for MyError { - fn respond_to(self, req: &'r Request<'_>) -> response::Result<'static> { - Scaffold { - title: "Error".to_string(), - content: markup::new! { - h2 { "An error occured. Nobody is sorry" } - pre.error { @format!("{:?}", self.0) } - }, - } - .respond_to(req) - } -} - -impl Display for MyError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.0.fmt(f) - } -} -// impl From for MyError { -// fn from(err: T) -> MyError { -// MyError(anyhow::anyhow!("{err}")) -// } -// } -impl From for MyError { - fn from(err: std::io::Error) -> MyError { - MyError(anyhow::anyhow!("{err}")) - } -} -impl From for MyError { - fn from(err: anyhow::Error) -> MyError { - MyError(err) - } -} diff --git a/src/layout.rs b/src/layout.rs deleted file mode 100644 index 637e2fc..0000000 --- a/src/layout.rs +++ /dev/null @@ -1,104 +0,0 @@ -/* -This file is part of metamuffins website (https://codeberg.org/metamuffin/website) -which is licensed under the GNU Affero General Public License (version 3); see /COPYING. -Copyright (C) 2023 metamuffin -*/ - -use crate::blog::rocket_uri_macro_r_blog; -use crate::pages::{ - rocket_uri_macro_r_about, rocket_uri_macro_r_contact, rocket_uri_macro_r_pgp_key, - rocket_uri_macro_r_stuff, -}; -use crate::projects::rocket_uri_macro_r_projects; -use crate::source::rocket_uri_macro_r_source; -use crate::uri; -use markup::{raw, Render}; -use rocket::{ - http::ContentType, - response::{self, Responder}, - Request, Response, -}; -use std::io::Cursor; - -markup::define! { - ScaffoldImpl( - title: String, - main: Main, - noimg: bool, - ) { - @markup::doctype() - html[lang="en"] { - head { - title { @title " - " "metamuffin's website" } - meta[name="viewport", content="width=device-width, initial-scale=1.0"]; - meta[name="description", content="metamuffin's personal website"]; // TODO - link[rel="stylesheet", href="/style.css"]; - } - body { - @if !noimg { img[ - src="https://s.metamuffin.org/avatar/default-512.webp", - alt="a muffin with purple glowing regions where a 3d vornoi function using chebychev distance exceeds some threshold", - align="left", - height=80, - width=80, - hspace=10, - ]; } - h1 { "metamuffin's personal website" } - nav { - a[href=uri!(r_about())] { "About" } " " - a[href=uri!(r_blog())] { "Blog" } " " - a[href=uri!(r_projects())] { "Projects" } " " - a[href=uri!(r_contact())] { "Contact" } " " - a[href=uri!(r_stuff())] { "Stuff" } " " - a[href="https://codeberg.org/metamuffin"] { "Codeberg" } " " - a[href=uri!(r_pgp_key())] { "PGP-Key" } " " - } - hr; - article { @main } - hr; - footer { - p { - "metamuffin's website; version " @include_str!("../.git/refs/heads/main")[0..10] "; " - "sources available on " a[href=uri!(r_source())] { "this page itself" } - " and on " a[href="https://codeberg.org/metamuffin/metamuffin-website"] { "codeberg" } - } - } - hr; - @if !noimg { - details.ad { summary { "Advertisement by a first-party" } - iframe[loading="lazy", src="https://adservices.metamuffin.org/v1/embed?s=metamuffin.org", style="width:728px;height:90px;border:none;"] {} - } - details.ad { summary { "Advertisement by a third-party" } - iframe[loading="lazy", src="https://john.citrons.xyz/embed?ref=metamuffin.org", style="width:732px;height:94px;border:none;"] {} - } - script { @raw("document.querySelectorAll(\".ad\").forEach(e=>e.open=true) // evil js enables ads hehe") } - } - } - } - } -} - -pub type DynScaffold<'a> = Scaffold>; - -pub struct Scaffold { - pub title: String, - pub content: T, -} - -impl<'r, Main: Render> Responder<'r, 'static> for Scaffold
{ - fn respond_to(self, _req: &'r Request<'_>) -> response::Result<'static> { - let mut out = String::new(); - ScaffoldImpl { - main: self.content, - noimg: self.title == "Source", - title: self.title, - } - .render(&mut out) - .unwrap(); - - Response::build() - .header(ContentType::HTML) - .streamed_body(Cursor::new(out)) - .ok() - } -} diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index b380491..0000000 --- a/src/main.rs +++ /dev/null @@ -1,67 +0,0 @@ -/* - This file is part of metamuffins website (https://codeberg.org/metamuffin/website) - which is licensed under the GNU Affero General Public License (version 3); see /COPYING. - Copyright (C) 2023 metamuffin -*/ -#![feature(const_trait_impl)] -pub mod blog; -pub mod error; -pub mod layout; -pub mod pages; -pub mod projects; -pub mod source; -pub mod wellknown; - -use blog::*; -use error::*; -use pages::*; -use projects::*; -use rocket::{catchers, fairing::AdHoc, fs::FileServer, http::Header, routes}; -use source::*; -use wellknown::*; - -#[tokio::main] -async fn main() { - env_logger::init_from_env("LOG"); - let _ = rocket::build() - .attach(AdHoc::on_response("set server header", |_req, res| { - res.set_header(Header::new("server", "blub")); - Box::pin(async {}) - })) - .manage(prepare_source()) - .mount("/blog/assets", FileServer::from(ASSET_ROOT)) - .mount( - "/", - routes![ - r_root, - r_about, - r_contact, - r_projects, - r_pgp_key, - r_source, - r_blog, - r_stuff, - r_hello, - r_favicon, - r_blog_index, - r_blog_article, - r_blog_atom, - r_style, - r_wellknown_security, - r_wellknown_matrix_server, - r_wellknown_matrix_client, - r_wellknown_flathub_verified, - ], - ) - .register("/", catchers![r_catch]) - .launch() - .await - .unwrap(); -} - -#[macro_export] -macro_rules! uri { - ($kk:stmt) => { - &rocket::uri!($kk).to_string() - }; -} diff --git a/src/pages.rs b/src/pages.rs deleted file mode 100644 index 4990491..0000000 --- a/src/pages.rs +++ /dev/null @@ -1,122 +0,0 @@ -use crate::uri; -use crate::{ - helper::get_articles, - layout::{DynScaffold, Scaffold}, - rocket_uri_macro_r_blog_article, ARTICLE_ROOT, -}; -use chrono::{NaiveTime, Utc}; -use rocket::{get, http::ContentType, response::Redirect}; -use std::{path::PathBuf, str::FromStr}; - -#[get("/")] -pub fn r_root() -> Redirect { - Redirect::to(rocket::uri!(r_about())) -} - -#[get("/hello")] -pub fn r_hello() -> &'static str { - "Hello World!" -} - -#[get("/about")] -pub async fn r_about<'a>() -> DynScaffold<'a> { - let articles = get_articles(&PathBuf::from_str(ARTICLE_ROOT).unwrap()) - .await - .unwrap_or_default(); - let mut newest = articles.first().cloned(); - if let Some(n) = &newest { - if n.date - .into_naive() - .unwrap() - .and_time(NaiveTime::default()) - .and_utc() - .signed_duration_since(Utc::now()) - .num_days() - < -8 - { - newest = None; - } - } - Scaffold { - title: "about".to_string(), - content: markup::new! { - @if let Some(a) = &newest { - .featured { - p { "Read the newest blog post: " a[href=uri!(r_blog_article(&a.canonical_name))] { @a.title } } - } - } - p { - "Hi. I am a normal person from planet earth. " - "I enjoy starting projects and never finishing them. " - "I do not know what to write here. " - "I am also supporting the free software movement by writing exclusively free software in my spare time. " - } - h2 { "current interests" } - ul { - li { "development of a general-purpose systems programming language" } - li { "development of multimedia processing and streaming applications" } - li { "replacing existing software with rust rewrites and rocket emotes" } - li { "stuff" } - } - h2 { "links" } - p { "some of my projects if you are here because of boredom: " } - ul { - li { a[href="https://meet.metamuffin.org"] { "keks-meet" } } - li { a[href="https://s.metamuffin.org/projects/weakpoint/"] { "weakpoint" } } - li { a[href="https://meet.metamuffin.org"] { "keks-meet" } } - } - - }, - } -} - -#[get("/contact")] -pub fn r_contact() -> DynScaffold<'static> { - Scaffold { - title: "contact".to_string(), - content: markup::new! { - p { "You can reach out to me in a bunch of ways. I am also generally looking for nice software ideas to implement." } - ul { - li { "matrix: " a[href="https://matrix.to/#/@metamuffin:metamuffin.org"]{"@metamuffin:metamuffin.org"} } - li { "fedi: " a[href="https://social.metamuffin.org/@metamuffin"]{"@metamuffin@social.metamuffin.org"} } - li { "electronic mail: " a[href="mailto:metamuffin@disroot.org"]{"metamuffin@disroot.org"} } - li { "telepathy: come on, just try hard enough" } - } - }, - } -} - -#[get("/stuff")] -pub fn r_stuff() -> DynScaffold<'static> { - Scaffold { - title: "stuff".to_string(), - content: markup::new! { - h1 { "Stuff" } - p { "I use arch btw." } - p { "The server uses arch btw." } - p { "My raspberry pi uses arch btw." } - p { "My router uses arch btw." } - p { "One of my smartphones uses arch btw." } - h2 { "Funny People" } - ul { - li { a[href="https://potatoxel.org"] { "Potatoxel" } } - li { a[href="https://pixificial.xyz"] { "Pixificial" } } - li { a[href="https://rustystriker.dev"] { "Rustystriker" } } - li { a[href="https://bgfxc4.de"] { "bgfxc4" } } - } - }, - } -} - -#[get("/favicon.ico")] -pub fn r_favicon() {} - -#[get("/key.asc")] -pub fn r_pgp_key() -> &'static str { - include_str!("../assets/key.asc") -} - -#[get("/style.css")] -pub fn r_style() -> (ContentType, &'static str) { - (ContentType::CSS, include_str!("../assets/style.css")) -} diff --git a/src/projects/data.rs b/src/projects/data.rs deleted file mode 100644 index a307b50..0000000 --- a/src/projects/data.rs +++ /dev/null @@ -1,393 +0,0 @@ -use super::{Project, State::*, Status::*}; - -pub const PROJECTS: &'static [Project] = &[ - Project { - name: "gnix", - status: Maintained, - description: "a stupid reverse proxy to replace nginx. serving the webpage you are viewing right now.", - link: Some("https://metamuffin.org"), - ..default() - }, - Project { - name: "keks-meet", - status: Maintained, - description: "a simple secure web conferencing application.", - link: Some("https://meet.metamuffin.org"), - ..default() - }, - Project { - name: "hurrycurry", - status: Maintained, - description: "A cooperative video game about cooking. Featuring multiplayer, 3d graphics and more.", - link: Some("https://hurrycurry.metamuffin.org"), - repo_link: Some("https://codeberg.org/hurrycurry/hurrycurry"), - ..default() - }, - Project { - name: "weareserver", - status: Developing, - description: "server software (and experimental client) for a generic 3d multiplayer game with VoIP capabilities. Inspired by VRChat and Minetest.", - ..default() - }, - Project { - name: "abrechenbarkeit", - status: Maintained, - description: "a simple trust-based ledger implemented as a Lua CGI web application with a CSV database", - ..default() - }, - Project { - name: "jellything", - status: Paused(Working), - description: "(paused until accumulated technical dept is fixed) media streaming solution (similiar to jellyfin). supports on-the-fly remuxing and federated content.", - ..default() - }, - Project { - name: "pfadfinder", - status: Paused(Working), - description: "parallel anytime A* for openstreetmap with custom frontend and integration into the existing one.", - ..default() - }, - Project { - name: "video-codec-experiments", - status: Paused(Working), - description: "a few attempts of creating my own video codecs, making use of motion compensation, dct, quantization and more. ", - ..default() - }, - Project { - name: "pixelflut tools", - status: Paused(Working), - description: "the programs I hacked together when playing pixelflut. includes GPU-acceleration for updating the canvas with minimal bandwidth usage.", - ..default() - }, - Project { - name: "attocc", - status: Paused(Unfinished), - description: "minimal C compiler in C", - ..default() - }, - Project { - name: "trash-proxy", - status: Maintained, - description: "A minecraft reverse proxy for offline authentification.", - ..default() - }, - Project { - name: "voxelwagen", - status: Paused(Unfinished), - description: "voxel game engine made from scratch; made to host an automation game.", - repo_link: Some("https://codeberg.org/voxelwagen/voxelwagen"), - ..default() - }, - Project { - name: "reCYCLING", - status: Developing, - description: "A fun CAPTCHA solution", - ..default() - }, - Project { - name: "keckup", - status: Maintained, - description: "Backup utility that traverses the filesystem while applying .gitignore and .backupignore files", - ..default() - }, - Project { - name: "ebml-struct", - status: Maintained, - description: "EBML parser and generator library with integrated Matroska types implemented in Rust without proc macros", - ..default() - }, -]; -pub const EXTRA_PROJECTS: &'static [Project] = &[ - Project { - name: "mond", - status: Paused(Unfinished), - description: "server monitoring software, no much code written so far", - ..default() - }, - Project { - name: "infra", - status: Paused(Working), - description: "multi-system installation manager. allows to centrally manage installations with a single configuration in form of a rust DSL", - ..default() - }, - Project { - name: "pbot", - status: Developing, - description: "Opinionated rust library for writing high-level chatbots that concurrently run on multiple messengers.", - ..default() - }, - Project { - name: "karlender", - status: Paused(Working), - description: " a personal calender suite consisting of a daemon, a graphical and a command-line user interface. supports very flexible condition based recurring tasks and automatic scheduling so you dont need to decide.", - ..default() - }, - Project { - name: "bad-editor", - status: Paused(Unfinished), - description: "A really bad editor", - ..default() - }, - Project { - name: "cosu", - status: Paused(Unfinished), - description: "a simple fast osu! client in c (not nearly a working client yet)", - ..default() - }, - Project { - name: "sprakc", - status: Abandoned(Working), - description: "A compiler from c++ to sprak", - ..default() - }, - Project { - name: "sprak-runtime", - status: Abandoned(Working), - description: "", - ..default() - }, - Project { - name: "ehb-data", - status: Abandoned(Working), - description: "", - ..default() - }, - Project { - name: "sgf", - status: Unknown, - description: "", - ..default() - }, - Project { - name: "circuit-simulator", - status: Unknown, - description: "", - ..default() - }, - Project { - name: "metabot", - status: Paused(Unfinished), - description: "", - ..default() - }, - Project { - name: "website", - status: Maintained, - description: "", - ..default() - }, - Project { - name: "ld49", - status: Abandoned(Unfinished), - description: "Ludum dare 49", - ..default() - }, - Project { - name: "bot-game", - status: Unknown, - description: "", - ..default() - }, - Project { - name: "game-platform", - status: Unknown, - description: "", - ..default() - }, - Project { - name: "simple-game-engine", - status: Paused(Unfinished), - description: "", - ..default() - }, - Project { - name: "voice-control", - status: Paused(Unfinished), - description: "", - ..default() - }, - Project { - name: "libreverse-old", - status: Abandoned(Unfinished), - description: "", - ..default() - }, - Project { - name: "golf-lang", - status: Abandoned(Unfinished), - description: "", - ..default() - }, - Project { - name: "mumble-music", - status: Paused(Unfinished), - description: "", - ..default() - }, - Project { - name: "muon", - status: Paused(Unfinished), - description: "", - ..default() - }, - Project { - name: "libresyncedvideoplayer", - status: Unknown, - description: "", - ..default() - }, - Project { - name: "fireworks", - status: Abandoned(Unfinished), - description: "Fireworks with Three.js", - ..default() - }, - Project { - name: "bj1", - status: Unknown, - description: "", - ..default() - }, - Project { - name: "so-survey", - status: Paused(Working), - description: "Some code for processing the stackoverflow developer survey's results", - ..default() - }, - Project { - name: "rubberkeys", - status: Abandoned(Working), - description: "", - ..default() - }, - Project { - name: "lunar-lander", - status: Abandoned(Working), - description: "", - ..default() - }, - Project { - name: "molecule-viewer", - status: Paused(Working), - description: "Web application to visualize layout of molecules", - ..default() - }, - Project { - name: "oxelpot", - status: Paused(Working), - description: "text-board service using pure html on the client", - ..default() - }, - Project { - name: "CUBE", - status: Abandoned(Unfinished), - description: "", - ..default() - }, - Project { - name: "godot-mumble-link", - status: Paused(Unfinished), - description: "", - ..default() - }, - Project { - name: "libreverse-server", - status: Unknown, - description: "2d multiplayer game engine server", - ..default() - }, - Project { - name: "twclient", - status: Paused(Unfinished), - description: "A teeworlds client in rust, based on libtw2", - ..default() - }, - Project { - name: "minetest_meta_uhc", - status: Paused(Unfinished), - description: "ultra hardcore mod for minetest with decreasing border size", - ..default() - }, - Project { - name: "guitar-chords", - status: Paused(Unfinished), - description: "", - ..default() - }, - Project { - name: "gnu-netcat", - status: Paused(Working), - description: "Mirror of the “GNU“ netcat utility (imported from CVS)", - ..default() - }, - Project { - name: "stonk-game", - status: Abandoned(Unfinished), - description: "simple game to compete in trading stocks", - ..default() - }, - Project { - name: "pw-patchbay", - status: Paused(Working), - description: "Tool to setup links for pipewire", - ..default() - }, - Project { - name: "desterr", - status: Maintained, - description: "dead simple tool to distinguish stderr and stdout", - ..default() - }, - Project { - name: "staticwiki", - status: Paused(Working), - description: "tools to convert MediaWiki XML dumps to static HTML pages", - ..default() - }, - Project { - name: "trash-map", - status: Paused(Working), - description: "A minecraft map renderer", - ..default() - }, - Project { - name: "acoustsearch", - status: Paused(Unfinished), - description: "Search the acoustid database locally.", - ..default() - }, - Project { - name: "meta_shell", - status: Paused(Unfinished), - description: "Simple wayland shell only including a status dock.", - ..default() - }, - Project { - name: "3d-frame-interpolation", - status: Paused(Working), - description: "", - ..default() - }, - Project { - name: "librelambda", - status: Paused(Working), - description: "A lambda calculus \"solver\".", - ..default() - }, - Project { - name: "automato", - status: Paused(Unfinished), - description: "A minimal, gridless automation game.", - ..default() - }, -]; - -const fn default() -> Project { - Project { - name: "", - status: super::Status::Unknown, - description: "", - link: None, - repo_link: None, - } -} diff --git a/src/projects/mod.rs b/src/projects/mod.rs deleted file mode 100644 index afb275f..0000000 --- a/src/projects/mod.rs +++ /dev/null @@ -1,88 +0,0 @@ -use self::data::{EXTRA_PROJECTS, PROJECTS}; -use crate::layout::{DynScaffold, Scaffold}; -use markup::Render; -use rocket::get; - -pub mod data; - -#[get("/projects")] -pub fn r_projects() -> DynScaffold<'static> { - Scaffold { - title: "projects".to_string(), - content: markup::new! { - p { "I am starting a lot of projects - this page lists some of them." } - p { - "Starting so many means, that most of then are not maintained or not even properly developed. " - "Here is a quick reference to what I define the status of a project to be: " - } - ol { - li { @Status::Planned.render() ": No code has been written yet." } - li { @Status::Developing.render() ": Project is under active development." } - li { @Status::Maintained.render() ": Project is in a working state and receives regular updates." } - li { @Status::Paused(State::Working).render() @Status::Paused(State::Unfinished).render() ": Project has been discontinued for an unspecified amount of time, but might be resumed if i feel like it." } - li { @Status::Abandoned(State::Working).render() @Status::Abandoned(State::Unfinished).render() ": Project has been discontinued and will likely not ever be continued." } - li { @Status::Unknown.render() ": I have not bothered to write down the status" } - } - ul { @for p in PROJECTS { li { @p } } } - details { summary { "Other not-so-important projects" } - ul { @for p in EXTRA_PROJECTS { li { @p } } } - } - }, - } -} - -#[derive(Debug, Clone, Copy)] -pub enum State { - Working, - Unfinished, -} - -#[derive(Debug, Clone, Copy)] -pub enum Status { - Unknown, - Planned, - Developing, - Paused(State), - Maintained, - Abandoned(State), -} - -markup::define! { Project( - name: &'static str, - status: Status, - description: &'static str, - link: Option<&'static str>, - repo_link: Option<&'static str> -) { - b { @name } - @status.render() - ": " @description - " (" - @if let Some(link) = link { - a[href=link] "Project page" - ", " - } - @let fallback = format!("https://codeberg.org/metamuffin/{name}"); - a[href=repo_link.unwrap_or(&fallback)] "Source code" - ")" -}} - -impl Status { - fn ident(self) -> &'static str { - match self { - Status::Unknown => "unknown", - Status::Planned => "planned", - Status::Developing => "developing", - Status::Maintained => "maintained", - Status::Paused(State::Unfinished) => "paused-unfinished", - Status::Paused(State::Working) => "paused-working", - Status::Abandoned(State::Unfinished) => "abandoned-unfinished", - Status::Abandoned(State::Working) => "abandoned-working", - } - } - pub fn render(self) -> impl Render { - markup::new! { - div[class=format!("status status-{}", self.ident())] { @format!("{self:?}") } - } - } -} diff --git a/src/source.rs b/src/source.rs deleted file mode 100644 index 04ec929..0000000 --- a/src/source.rs +++ /dev/null @@ -1,80 +0,0 @@ -use crate::layout::{DynScaffold, Scaffold}; -use rocket::{ - get, - http::Header, - response::{self, Responder}, - Request, State, -}; -use std::time::{Duration, SystemTime, UNIX_EPOCH}; - -pub struct Reload(pub T); - -#[rocket::async_trait] -impl<'r, T: Responder<'r, 'static>> Responder<'r, 'static> for Reload { - fn respond_to(self, request: &'r Request<'_>) -> response::Result<'static> { - let mut resp = self.0.respond_to(request); - if let Ok(resp) = &mut resp { - resp.set_header(Header::new("refresh", "0")); - } - resp - } -} - -const SOURCE_DIR: include_dir::Dir = include_dir::include_dir!("$CARGO_MANIFEST_DIR/src"); - -pub struct SourceWrap(Vec); - -pub fn prepare_source() -> SourceWrap { - SourceWrap( - SOURCE_DIR - .find("**/*.rs") - .unwrap() - .map(|f| { - format!( - " -====================================== - Contents of {:?} -====================================== -{} -", - f.path(), - f.as_file().unwrap().contents_utf8().unwrap() - ) - }) - .collect::>() - .join("\n") - .split("\n") - .map(String::from) - .collect(), - ) -} - -#[get("/source")] -pub async fn r_source(text: &State) -> Reload { - let mspf = 100u128; - - let ts = SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_millis(); - - let frame = ts / mspf; - let frame_off = ts % mspf; - - tokio::time::sleep(Duration::from_millis((mspf - frame_off) as u64)).await; - - let mut out = String::new(); - out += &format!( - "About {} milliseconds have passed since midnight of the january the first in 1970.\n", - ts - ); - out += "------------------------------------------------------\n"; - for i in frame..frame + 30 { - out += &text.0[(i % text.0.len() as u128) as usize]; - out += "\n"; - } - Reload(Scaffold { - title: "Source".to_string(), - content: markup::new! { pre { @out } }, - }) -} diff --git a/src/wellknown.rs b/src/wellknown.rs deleted file mode 100644 index ee800c2..0000000 --- a/src/wellknown.rs +++ /dev/null @@ -1,40 +0,0 @@ -use rocket::{ - get, - http::Header, - response::{self, Responder}, - serde::json::{json, Value}, - Request, -}; - -pub struct Cors(pub T); - -#[rocket::async_trait] -impl<'r, T: Responder<'r, 'static>> Responder<'r, 'static> for Cors { - fn respond_to(self, request: &'r Request<'_>) -> response::Result<'static> { - let mut resp = self.0.respond_to(request); - if let Ok(resp) = &mut resp { - resp.set_header(Header::new("access-control-allow-origin", "*")); - } - resp - } -} - -#[get("/.well-known/matrix/client")] -pub fn r_wellknown_matrix_client() -> Cors { - Cors(json!({"m.homeserver": {"base_url": "https://matrix.metamuffin.org"}} )) -} - -#[get("/.well-known/matrix/server")] -pub fn r_wellknown_matrix_server() -> Cors { - Cors(json!({"m.server": "matrix.metamuffin.org:443"} )) -} - -#[get("/.well-known/security.txt")] -pub fn r_wellknown_security() -> &'static str { - include_str!("../assets/security.txt.asc") -} - -#[get("/.well-known/org.flathub.VerifiedApps.txt")] -pub fn r_wellknown_flathub_verified() -> &'static str { - "a29f43db-bd4e-40cb-b121-2899c4d70634\n" -} -- cgit v1.2.3-70-g09d2