summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2025-10-02 19:14:17 +0200
committermetamuffin <metamuffin@disroot.org>2025-10-02 19:14:17 +0200
commit23871d5aadcaa4d01b7c46cb951854572940414d (patch)
tree9a3f0490675642a5b76bdda8f44f2e75b469046c /src
parentfbc308f96dca2854bc462e6fee412b5dc35b6c3c (diff)
downloadmetamuffin-website-23871d5aadcaa4d01b7c46cb951854572940414d.tar
metamuffin-website-23871d5aadcaa4d01b7c46cb951854572940414d.tar.bz2
metamuffin-website-23871d5aadcaa4d01b7c46cb951854572940414d.tar.zst
Rewrite
Diffstat (limited to 'src')
-rw-r--r--src/blog/atom.rs75
-rw-r--r--src/blog/helper.rs72
-rw-r--r--src/blog/mod.rs146
-rw-r--r--src/error.rs59
-rw-r--r--src/layout.rs104
-rw-r--r--src/main.rs67
-rw-r--r--src/pages.rs122
-rw-r--r--src/projects/data.rs393
-rw-r--r--src/projects/mod.rs88
-rw-r--r--src/source.rs80
-rw-r--r--src/wellknown.rs40
11 files changed, 0 insertions, 1246 deletions
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<String> {
- 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#"
- <entry>
- <title>{title}</title>
- <link href="{href}" />
- <id>tag:metamuffin.org,{date},{canonical_name}</id>
- <published>{datetime}</published>
- <summary>N/A</summary>
- <author>
- <name>metamuffin</name>
- <email>metamuffin@disroot.org</email>
- </author>
- </entry>"#
- )
- },
- )
- .collect::<Vec<_>>();
-
- let feed_url = uri!(r_blog_atom());
- let index_url = uri!(r_blog_index());
- let now = chrono::Utc::now().to_rfc3339();
-
- Ok(format!(
- r#"<?xml version="1.0" encoding="utf-8"?>
-<feed xmlns="http://www.w3.org/2005/Atom">
- <title>metamuffin's blog</title>
- <subtitle>where they post pointless stuff</subtitle>
- <link href="{feed_url}" rel="self" />
- <link href="{index_url}" />
- <id>urn:uuid:3cf2b704-3d94-4f1f-b194-42798ab5b47c</id>
- <updated>{now}</updated>
- <author>
- <name>metamuffin</name>
- <email>metamuffin@disroot.org</email>
- </author>
- {}
-</feed>
- "#,
- entries.join("\n")
- ))
-}
-
-pub fn horrible_escape_function(text: &str) -> String {
- text.replace("&", "&amp;")
- .replace("<", "&lt;")
- .replace(">", "&gt;")
- .replace("'", "&#8217;")
- .replace("\"", "&quot;")
-}
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<ArticleMeta> {
- 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<Vec<ArticleMeta>> {
- 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::<anyhow::Result<Vec<_>>>()?;
- 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<DynScaffold<'static>> {
- // 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/<name>")]
-pub async fn r_blog_article(name: &str) -> MyResult<DynScaffold<'static>> {
- 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<T> = Result<T, MyError>;
-
-#[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<T: std::error::Error> From<T> for MyError {
-// fn from(err: T) -> MyError {
-// MyError(anyhow::anyhow!("{err}"))
-// }
-// }
-impl From<std::io::Error> for MyError {
- fn from(err: std::io::Error) -> MyError {
- MyError(anyhow::anyhow!("{err}"))
- }
-}
-impl From<anyhow::Error> 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 <metamuffin.org>
-*/
-
-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<Main: Render>(
- 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<markup::DynRender<'a>>;
-
-pub struct Scaffold<T> {
- pub title: String,
- pub content: T,
-}
-
-impl<'r, Main: Render> Responder<'r, 'static> for Scaffold<Main> {
- 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 <metamuffin.org>
-*/
-#![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<T>(pub T);
-
-#[rocket::async_trait]
-impl<'r, T: Responder<'r, 'static>> Responder<'r, 'static> for Reload<T> {
- 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<String>);
-
-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::<Vec<_>>()
- .join("\n")
- .split("\n")
- .map(String::from)
- .collect(),
- )
-}
-
-#[get("/source")]
-pub async fn r_source(text: &State<SourceWrap>) -> Reload<DynScaffold> {
- 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<T>(pub T);
-
-#[rocket::async_trait]
-impl<'r, T: Responder<'r, 'static>> Responder<'r, 'static> for Cors<T> {
- 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<Value> {
- Cors(json!({"m.homeserver": {"base_url": "https://matrix.metamuffin.org"}} ))
-}
-
-#[get("/.well-known/matrix/server")]
-pub fn r_wellknown_matrix_server() -> Cors<Value> {
- 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"
-}