Initial support to Gemini protocol
parent
42b4285ae9
commit
90513d4007
|
@ -16,3 +16,7 @@ comrak = "0.24.1"
|
|||
tera = "1.19.1"
|
||||
isbot = "0.1.3"
|
||||
once_cell = "1.19.0"
|
||||
windmark = { version = "0.3.10", features = ["response-macros", "logger"] }
|
||||
tokio = { version = "1.26.0", features = ["full"] }
|
||||
md2gemtext = "0.1.0"
|
||||
glob = "0.3.1"
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
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
|
||||
-----END CERTIFICATE-----
|
|
@ -0,0 +1,54 @@
|
|||
-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||
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
|
||||
mwFIH5TpX3CFJXdlZybNcA==
|
||||
-----END ENCRYPTED PRIVATE KEY-----
|
|
@ -0,0 +1,86 @@
|
|||
use codigocomentado::*;
|
||||
|
||||
use controllers::posts;
|
||||
use dotenv::dotenv;
|
||||
use misc::{gen_title, replace_tables};
|
||||
use tera::Tera;
|
||||
use tokio::sync::OnceCell;
|
||||
|
||||
static TERA: OnceCell<Tera> = OnceCell::const_new();
|
||||
|
||||
async fn render<S: AsRef<str>>(name: S, context: &tera::Context) -> Result<String, ()> {
|
||||
let tera = TERA
|
||||
.get_or_init(|| async {
|
||||
let mut tera = Tera::default();
|
||||
for path in glob::glob("templates/gemini/*").unwrap().flatten() {
|
||||
let raw_path = path.clone();
|
||||
let filename = raw_path
|
||||
.file_name()
|
||||
.unwrap() // This should be safe (?
|
||||
.to_str()
|
||||
.unwrap() // ._.?
|
||||
.split('.')
|
||||
.next();
|
||||
tera.add_template_file(path, filename).unwrap()
|
||||
}
|
||||
tera
|
||||
})
|
||||
.await;
|
||||
tera.render(name.as_ref(), context).map_err(|_| ())
|
||||
}
|
||||
|
||||
#[windmark::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
dotenv().ok();
|
||||
|
||||
windmark::router::Router::new()
|
||||
.set_private_key_file("key.pem")
|
||||
.set_certificate_file("cert.pem")
|
||||
.set_languages(["es"])
|
||||
.enable_default_logger(true)
|
||||
.set_fix_path(true)
|
||||
.mount("/", move |_| {
|
||||
let (posts, _) = posts::get_posts(None);
|
||||
let mut context = tera::Context::new();
|
||||
|
||||
context.insert("title", &gen_title());
|
||||
context.insert("posts", &posts);
|
||||
|
||||
async move {
|
||||
windmark::response::Response::success(render("index", &context).await.unwrap())
|
||||
}
|
||||
})
|
||||
.mount("/post/:title", |request| {
|
||||
let title_splited: Vec<&str> = request
|
||||
.parameters
|
||||
.get("title")
|
||||
// This should be safe because its requires the parameter to enter to the route
|
||||
.unwrap()
|
||||
.split('-')
|
||||
.collect();
|
||||
let id = title_splited.last().unwrap().parse().unwrap_or(-1);
|
||||
async move {
|
||||
let result = match posts::get_post(id) {
|
||||
Ok(post) => {
|
||||
let mut context = tera::Context::new();
|
||||
let content = replace_tables(post.content)
|
||||
.replace("<pre>", "```")
|
||||
.replace("</pre>", "```");
|
||||
|
||||
context.insert("header", &gen_title());
|
||||
context.insert("title", &post.title);
|
||||
context.insert("created_at", &post.created_at);
|
||||
context.insert("content", &content);
|
||||
render("post", &context).await.unwrap()
|
||||
}
|
||||
Err(_) => "No se encontró ningún Post :c".into(),
|
||||
};
|
||||
windmark::response::Response::success(result)
|
||||
}
|
||||
})
|
||||
.set_error_handler(|_| {
|
||||
windmark::response::Response::permanent_failure("This route does not exist!")
|
||||
})
|
||||
.run()
|
||||
.await
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
pub mod admin;
|
||||
pub mod contexts;
|
||||
pub mod controllers;
|
||||
pub mod misc;
|
||||
pub mod models;
|
||||
mod schema;
|
||||
|
||||
#[macro_use]
|
||||
extern crate diesel;
|
||||
|
||||
#[macro_use]
|
||||
extern crate rocket;
|
11
src/main.rs
11
src/main.rs
|
@ -1,15 +1,12 @@
|
|||
pub mod admin;
|
||||
pub mod contexts;
|
||||
pub mod controllers;
|
||||
pub mod misc;
|
||||
pub mod models;
|
||||
mod schema;
|
||||
|
||||
#[macro_use]
|
||||
extern crate rocket;
|
||||
#[macro_use]
|
||||
extern crate diesel;
|
||||
|
||||
#[macro_use]
|
||||
extern crate rocket;
|
||||
|
||||
use codigocomentado::*;
|
||||
use comrak::{markdown_to_html, Options};
|
||||
use controllers::posts;
|
||||
use dotenv::dotenv;
|
||||
|
|
92
src/misc.rs
92
src/misc.rs
|
@ -20,3 +20,95 @@ pub fn gen_title() -> String {
|
|||
let title = str::replace(title_fmt, "{}", "CódigoComentado");
|
||||
title.to_string()
|
||||
}
|
||||
|
||||
pub fn ascii_table(raw_table: String) -> String {
|
||||
let raw_table = raw_table.trim();
|
||||
let mut new_table: Vec<Vec<Vec<String>>> = Vec::new();
|
||||
let mut max_width: Option<Vec<usize>> = None;
|
||||
let mut result = String::new();
|
||||
|
||||
for line in raw_table.lines() {
|
||||
let items: Vec<String> = line.split('|').map(|s| s.to_string()).collect();
|
||||
let mut new_items: Vec<Vec<String>> = vec![Vec::new(); items.len()];
|
||||
|
||||
if max_width.is_none() {
|
||||
max_width = Some(vec![0; items.len()]);
|
||||
}
|
||||
|
||||
for (n, item) in items.iter().enumerate() {
|
||||
let item = item
|
||||
.replace("<b>", "")
|
||||
.replace("</b>", "")
|
||||
.replace("<pre>", "")
|
||||
.replace("</pre>", "")
|
||||
.replace("\\", "");
|
||||
let split_items: Vec<String> = item.split("<br>").map(|s| s.to_string()).collect();
|
||||
new_items[n].clone_from(&split_items);
|
||||
let max_local = split_items.iter().map(|s| s.len()).max().unwrap_or(0);
|
||||
if let Some(ref mut mw) = max_width {
|
||||
mw[n] = std::cmp::max(mw[n], max_local);
|
||||
}
|
||||
}
|
||||
|
||||
new_table.push(new_items);
|
||||
}
|
||||
|
||||
for row in new_table {
|
||||
let max_height = row.iter().map(|col| col.len()).max().unwrap_or(0);
|
||||
for index in 0..(row.len() * max_height) {
|
||||
let index_subrow = index / row.len();
|
||||
let index_col = index % row.len();
|
||||
let text = if let Some(col) = row.get(index_col) {
|
||||
if let Some(&ref text) = col.get(index_subrow) {
|
||||
text
|
||||
} else {
|
||||
&String::from("")
|
||||
}
|
||||
} else {
|
||||
&String::from("")
|
||||
};
|
||||
let text = text.trim_end();
|
||||
if let Some(ref mw) = max_width {
|
||||
result.push_str(&format!(
|
||||
"{:width$}{}",
|
||||
text,
|
||||
if index_col < row.len() - 1 { "|" } else { "\n" },
|
||||
width = mw[index_col]
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
format!("```\n{}\n```\n", result)
|
||||
}
|
||||
|
||||
pub fn replace_tables(text: String) -> String {
|
||||
let mut result = String::new();
|
||||
let mut table: Option<String> = None;
|
||||
let mut is_code = false;
|
||||
|
||||
for line in text.lines() {
|
||||
if line.starts_with('|') & !is_code {
|
||||
if table.is_none() {
|
||||
table = Some(String::new());
|
||||
}
|
||||
if let Some(ref mut tab) = table {
|
||||
tab.push_str(&format!("{}\n", line));
|
||||
}
|
||||
} else {
|
||||
let temp = match table {
|
||||
Some(ref tab) => {
|
||||
println!("raw:\n{}", tab);
|
||||
let new_table = ascii_table(tab.to_string());
|
||||
println!("formated:\n{}", new_table);
|
||||
table = None;
|
||||
new_table
|
||||
}
|
||||
None => line.to_string(),
|
||||
};
|
||||
result.push_str(&temp);
|
||||
result.push('\n');
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
# {{ title }}
|
||||
|
||||
¡Hola!, acabas de aterrizar en mi cápsula, puedes tomar asiento donde gustes.
|
||||
Me presento, en el mundo de los internets decidí que mi apodo sería "kirbylife" y de vez en cuando me gusta escribir sobre cosas de programación y todo lo relacionado con las computadoras en general, y para hacerlo me creé un blog en la web de los hipertextos y por fin decidí a traerla a este otro espacio de internet, espero les guste lo que leen y, con un poco de suerte, le encuentren utilidad.
|
||||
|
||||
## Artículos
|
||||
{% for post in posts %}
|
||||
=> /post/{{ post.title | slugify }}-{{ post.id }} {{ post.title }}
|
||||
{{ post.content | split(pat=" ") | slice(end=30) | join(sep=" ") | split(pat="#") | slice(end=1) | join(sep="") | replace(from="\n", to="") | trim }}...
|
||||
{% endfor %}
|
||||
|
||||
## Info
|
||||
Este blog está escrito en el lenguaje de programación Rust, utilizando el framework Windmark, con el editor Emacs y cuenta con feeds RSS/Atom.
|
||||
=> https://blog.kirbylife.dev/feed.xml RSS
|
||||
=> https://blog.kirbylife.dev/atom.xml Atom
|
||||
|
||||
## Contacto
|
||||
En caso de que quieran contactarme por la razón que sea, pueden hacerlo por cualquiera de estos medios:
|
||||
Correo electrónico
|
||||
* hola(at)kirbylife.dev
|
||||
Mastodon
|
||||
* @kirbylife@mstdn.mx
|
||||
Telegram
|
||||
* @kirbylife
|
|
@ -0,0 +1,7 @@
|
|||
# {{ header }}
|
||||
=> / Volver al inicio
|
||||
|
||||
# {{ title }}
|
||||
Publicado el: {{ created_at | date(format="%Y-%m-%d") }}
|
||||
|
||||
{{ content | striptags }}
|
Loading…
Reference in New Issue