2025-04-26 11:17:58 +03:00
|
|
|
use axum;
|
|
|
|
|
use std::io;
|
|
|
|
|
use std::fs;
|
|
|
|
|
use std::collections::HashMap;
|
|
|
|
|
use axum::http::HeaderValue;
|
|
|
|
|
use std::path::{Path, PathBuf};
|
|
|
|
|
use std::sync::Arc;
|
|
|
|
|
use axum::http;
|
|
|
|
|
use mtgott::dirsearch::{search_dir, get_root_html};
|
|
|
|
|
use mtgott::runtime::{MTGOTT, Value};
|
|
|
|
|
use std::error::Error;
|
|
|
|
|
|
|
|
|
|
struct StaticAsset {
|
|
|
|
|
content_type: HeaderValue,
|
|
|
|
|
content: Vec<u8>
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct AssetsCache {
|
|
|
|
|
static_assets: HashMap<String, StaticAsset>,
|
|
|
|
|
pages: MTGOTT,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct ExtensionContentTypeCorr{
|
|
|
|
|
extension: &'static str,
|
|
|
|
|
content_type: HeaderValue,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn load_static_assets(p: &str, need: &[ExtensionContentTypeCorr]) -> Result<HashMap<String, StaticAsset>, Box<dyn Error>> {
|
|
|
|
|
let e: Vec<&'static str> = need.iter().map(|corr: &ExtensionContentTypeCorr| corr.extension).collect();
|
|
|
|
|
let content = search_dir(p, &e, &(|_| true))?;
|
|
|
|
|
let mut st: HashMap<String, StaticAsset> = HashMap::new();
|
|
|
|
|
for i in 0..need.len() {
|
|
|
|
|
let extension: &str = need[i].extension;
|
|
|
|
|
let content_type: &HeaderValue = &need[i].content_type;
|
|
|
|
|
for virtual_path in &content[i] {
|
|
|
|
|
let path_org = format!("{p}/{virtual_path}{extension}");
|
|
|
|
|
st.insert(format!("{virtual_path}{extension}"), StaticAsset{
|
|
|
|
|
content_type: content_type.clone(),
|
|
|
|
|
content: fs::read(&path_org)?,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Ok(st)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn load_needed_static_assets(p: &str) -> Result<HashMap<String, StaticAsset>, Box<dyn Error>> {
|
|
|
|
|
load_static_assets(p, &[
|
|
|
|
|
ExtensionContentTypeCorr{extension: ".css", content_type: HeaderValue::from_str("text/css").unwrap()},
|
|
|
|
|
ExtensionContentTypeCorr{extension: ".jpeg", content_type: HeaderValue::from_str("image/jpeg").unwrap()},
|
|
|
|
|
ExtensionContentTypeCorr{extension: ".jpg", content_type: HeaderValue::from_str("image/jpeg").unwrap()},
|
|
|
|
|
ExtensionContentTypeCorr{extension: ".png", content_type: HeaderValue::from_str("image/png").unwrap()},
|
|
|
|
|
])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl AssetsCache {
|
|
|
|
|
fn load_assets(assets_dir: &str) -> Result<AssetsCache, Box<dyn Error>> {
|
|
|
|
|
Ok(AssetsCache {
|
|
|
|
|
static_assets: load_needed_static_assets(assets_dir)?,
|
|
|
|
|
pages: get_root_html(&format!("{assets_dir}/HypertextPages"))?
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async fn static_assets(
|
|
|
|
|
axum::extract::Path(path): axum::extract::Path<String>,
|
|
|
|
|
axum::extract::State(assets): axum::extract::State<Arc<AssetsCache>>,
|
|
|
|
|
) -> Result<([(axum::http::HeaderName, axum::http::HeaderValue); 1], Vec<u8>), axum::http::StatusCode> {
|
|
|
|
|
if let Some(file) = assets.static_assets.get(&path) {
|
|
|
|
|
return Ok((
|
|
|
|
|
[(http::header::CONTENT_TYPE, file.content_type.clone())],
|
|
|
|
|
file.content.clone()
|
|
|
|
|
))
|
|
|
|
|
}
|
|
|
|
|
Err(axum::http::StatusCode::NOT_FOUND)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async fn page_index(
|
|
|
|
|
axum::extract::State(assets): axum::extract::State<Arc<AssetsCache>>,
|
|
|
|
|
// axum::extract::Extension(t): axum::extract::Extension<tera::Tera>
|
|
|
|
|
) -> axum::response::Html<String> {
|
|
|
|
|
let gr = Value::Int(0);
|
|
|
|
|
axum::response::Html(assets.pages.render(gr, "index", 500).unwrap())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async fn page_blog(
|
|
|
|
|
axum::extract::State(assets): axum::extract::State<Arc<AssetsCache>>,
|
|
|
|
|
// axum::extract::Extension(t): axum::extract::Extension<tera::Tera>
|
|
|
|
|
) -> impl axum::response::IntoResponse {
|
|
|
|
|
// let mut context = tera::Context::new();
|
|
|
|
|
// context.insert("lang", &assets.missing_text[0].0);
|
|
|
|
|
// context.insert("pres", &assets.missing_text[0].1);
|
|
|
|
|
// axum::response::Html(assets.templates.render("blog.html", &context).expect("Tera failure"))
|
|
|
|
|
axum::response::Html(String::new())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async fn fallback_page() -> axum::http::StatusCode {
|
|
|
|
|
axum::http::StatusCode::NOT_FOUND
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub async fn run_yyyi_ru() {
|
|
|
|
|
let assets_dir = format!("{}/assets", env!("CARGO_MANIFEST_DIR"));
|
|
|
|
|
let address = "0.0.0.0:3000";
|
|
|
|
|
println!("Assets dir: {assets_dir:?}");
|
|
|
|
|
|
|
|
|
|
let assets = Arc::new(AssetsCache::load_assets(&assets_dir).unwrap());
|
|
|
|
|
|
|
|
|
|
// build our application with a single route
|
|
|
|
|
let app = axum::Router::new()
|
|
|
|
|
.without_v07_checks()
|
|
|
|
|
.route("/", axum::routing::MethodRouter::new().get(page_index))
|
|
|
|
|
.route("/assets/{*path}", axum::routing::get(static_assets))
|
|
|
|
|
.route("/blog", axum::routing::get(page_blog))
|
|
|
|
|
.fallback(fallback_page).with_state(assets);
|
|
|
|
|
// .layer(axum::Extension(templates));
|
|
|
|
|
|
|
|
|
|
// run our app with hyper, listening globally on port 3000
|
|
|
|
|
let listener = tokio::net::TcpListener::bind(address).await.unwrap();
|
|
|
|
|
println!("Running on http://{address}");
|
|
|
|
|
axum::serve(listener, app).await.unwrap();
|
|
|
|
|
}
|