use std::fs; use std::sync::Arc; use anyhow::anyhow; use http_types::mime; use tide::prelude::*; use tide::Request; use crate::datafiles::*; use crate::format::*; use crate::*; pub async fn server_main() -> tide::Result<()> { // ---- load data files ---- eprintln!("Loading JMdict_e.xml..."); let jmdict_raw = fs::read_to_string("data/JMdict_e.xml").expect("read_jmdict"); let jmdict_raw: &'static str = String::leak(jmdict_raw); eprintln!("Parsing JMdict_e.xml..."); let jmdict = roxmltree::Document::parse_with_options( &jmdict_raw, roxmltree::ParsingOptions { allow_dtd: true, ..Default::default() }, ) .expect("parse_jmdict"); let jmdict_xml = Box::leak(Box::new(jmdict)); eprintln!("Indexing JMdict_e.xml..."); let jmdict_idx = index_jmdict(jmdict_xml); eprintln!("Loading batches.json..."); let batches = read_batches().expect("read/parse"); let batches = Box::leak(batches.into_boxed_slice()); eprintln!("Loading kanji levels..."); let kanji_levels = read_kanji_levels().expect("read_kanji_levels"); let mut index_bytes = Vec::new(); format_index_to(&mut index_bytes, &batches, &kanji_levels).unwrap(); let index = String::leak(String::from_utf8(index_bytes).unwrap()); // ---- setup http server ---- let state = Arc::new(StateStruct { jmdict_raw, jmdict_xml, jmdict_idx, batches, index, }); let mut app = tide::with_state(state); app.with(tide::log::LogMiddleware::new()); app.at("/").get(home_page); app.at("/index.html").get(home_page); app.at("/style.css").serve_file("static/style.css")?; app.at("/about.html").get(about_page); app.at("/:batch").get(batch_page); // ---- serve actual http ---- eprintln!("Server listening on 127.0.0.1:8080"); app.listen("127.0.0.1:8080").await?; Ok(()) } type State = Arc; #[allow(dead_code)] struct StateStruct { jmdict_raw: &'static str, jmdict_xml: &'static roxmltree::Document<'static>, jmdict_idx: DictIndex<'static>, batches: &'static [Batch], index: &'static str, } async fn home_page(req: Request) -> tide::Result { Ok(tide::Response::builder(200) .body(req.state().index) .content_type(mime::HTML) .build()) } async fn about_page(_req: Request) -> tide::Result { let mut about = Vec::new(); format_about_to(&mut about)?; Ok(tide::Response::builder(200) .body(about) .content_type(mime::HTML) .build()) } async fn batch_page(req: Request) -> tide::Result { let batch_idx = req.param("batch")?; let batch_idx: usize = batch_idx .strip_suffix(".html") .unwrap_or(batch_idx) .parse()?; let batch = req .state() .batches .get(batch_idx) .ok_or(anyhow!("this batch number does not exist"))?; let mut buf = vec![]; format_batch_to( &mut buf, &req.state().jmdict_idx, req.state().batches.len(), batch_idx, batch, )?; Ok(tide::Response::builder(200) .body(buf) .content_type(mime::HTML) .build()) }