aboutsummaryrefslogtreecommitdiff
path: root/src/server.rs
diff options
context:
space:
mode:
authorAlex Auvolat <alex@adnab.me>2024-03-11 00:37:59 +0100
committerAlex Auvolat <alex@adnab.me>2024-03-11 00:37:59 +0100
commitec546004d3b1619c12574f5c0aa0fc4272b7201f (patch)
treedbc99900e483fb565a8c06c94eed793334d944c3 /src/server.rs
parentd80afc4b77a2d34272e29914280859c836d9efd0 (diff)
downloaddatagengo-ec546004d3b1619c12574f5c0aa0fc4272b7201f.tar.gz
datagengo-ec546004d3b1619c12574f5c0aa0fc4272b7201f.zip
first interface for generated examples
Diffstat (limited to 'src/server.rs')
-rw-r--r--src/server.rs123
1 files changed, 102 insertions, 21 deletions
diff --git a/src/server.rs b/src/server.rs
index 58c4dee..c90ee40 100644
--- a/src/server.rs
+++ b/src/server.rs
@@ -1,8 +1,8 @@
use std::fs;
use std::io::Write;
-use std::sync::Arc;
-use anyhow::anyhow;
+use futures::stream::TryStreamExt;
+use anyhow::{anyhow, Result};
use rand::prelude::*;
use http_types::mime;
@@ -10,6 +10,7 @@ use tide::Request;
use crate::datafiles::*;
use crate::format::*;
+use crate::example::*;
use crate::*;
pub async fn server_main() -> tide::Result<()> {
@@ -64,7 +65,7 @@ pub async fn server_main() -> tide::Result<()> {
// ---- setup http server ----
- let state = Arc::new(StateStruct {
+ let state: State = Box::leak(Box::new(StateStruct {
jmdict_raw,
jmdict_xml,
jmdict_idx,
@@ -73,7 +74,7 @@ pub async fn server_main() -> tide::Result<()> {
examples,
example_freq,
furigana_overrides,
- });
+ }));
let mut app = tide::with_state(state);
app.with(tide::log::LogMiddleware::new());
@@ -81,6 +82,8 @@ pub async fn server_main() -> tide::Result<()> {
app.at("/").get(home_page);
app.at("/index.html").get(home_page);
app.at("/style.css").serve_file("static/style.css")?;
+ app.at("/script.js").serve_file("static/script.js")?;
+ app.at("/jquery.js").serve_file("static/jquery.js")?;
app.at("/about.html").get(about_page);
app.at("/ex/:start/:end").get(gen_examples_page);
app.at("/:batch").get(batch_page);
@@ -93,7 +96,7 @@ pub async fn server_main() -> tide::Result<()> {
Ok(())
}
-type State = Arc<StateStruct>;
+type State = &'static StateStruct;
#[allow(dead_code)]
struct StateStruct {
jmdict_raw: &'static str,
@@ -172,18 +175,92 @@ async fn gen_examples_page(req: Request<State>) -> tide::Result {
.flatten(),
);
- let mut examples = gen_examples(&req.state(), &allowed_chars, &needed_chars, 50);
- for ex in examples.iter_mut() {
- ex.gen_furigana(&req.state().jmdict_idx, &req.state().furigana_overrides);
- }
+ let (tx, rx) = async_channel::unbounded();
+
+ let state: State = req.state();
+ std::thread::spawn(move || {
+ tx.send_blocking(Ok(format!(r#"
+ <!DOCTYPE html>
+ <html>
+ <head>
+ <meta charset=\"UTF-8\" />
+ <title>{:03} - {:03} practice</title>
+ <link rel="stylesheet" type="text/css" href="/style.css" />
+ <script src="/jquery.js"></script>
+ <script src="/script.js"></script>
+ </head>
+ <body>
+ <div class="batch_page">
+ <p><a href="index.html">index</a></p>
+ <p>Practice for {:03} - {:03}</p>
+ <hr />
+ <div id="gen_section">
+ <div id="gen_ex_cnt">
+ </div>
+ <div id="gen_ex_display">
+ </div>
+ <div id="gen_ex_en">
+ </div>
+ <div id="gen_ex_words" class="vocabtable">
+ </div>
+ </div>
+ </div>
+ </body>
+ "#, first_level, last_level, first_level, last_level).into_bytes()))?;
+
+ gen_examples(state, &allowed_chars, &needed_chars, 50, |mut ex| {
+ ex.gen_furigana(&req.state().jmdict_idx, &req.state().furigana_overrides);
+
+ let mut expl = "<table>".to_string();
+ for word in ex.expl.split(|c| c == ' ' || c == '~') {
+ let (keb, reb) = expl_clean_word(word);
+ let wchars = Charset::new(keb);
+ if !wchars.intersects(&allowed_chars) {
+ continue;
+ }
+ if let Some(ents) = state.jmdict_idx.get(keb) {
+ for ent in ents.iter() {
+ let ent_r_ele = ent.children().find(|x| x.has_tag_name("r_ele")).unwrap();
+ let ent_reb = ent_r_ele.children().find(|x| x.has_tag_name("reb")).unwrap();
+ let ent_reb = ent_reb.text().unwrap().trim();
+ if reb.map(|x| x != ent_reb).unwrap_or(false) {
+ continue;
+ }
+ expl += &format!(r#"<tr><td style="word-break: keep-all">&nbsp;&nbsp;<span class="tab_large font_ja">{}</span>&nbsp;&nbsp;</td><td width="50%">"#, keb);
+
+ for sense in ent.children().filter(|x| x.has_tag_name("sense")) {
+ if let Some(s) = sense.children().find(|x| x.has_tag_name("gloss")) {
+ if !expl.ends_with('>') {
+ expl += "; ";
+ }
+ expl += s.text().unwrap().trim();
+ }
+ }
+ expl += &format!(r#"</td><td style="word-break: keep-all" class="tab_large font_ja">{}</td></tr>"#, ent_reb);
+ }
+ }
+ }
- let mut buf: Vec<u8> = vec![];
- for ex in examples.iter() {
- write!(&mut buf, "<p>{}</p>", ex.furigana_markup())?;
- }
+ let item = serde_json::json!({
+ "ja": ex.ja,
+ "en": ex.en,
+ "furi": ex.furigana_markup(),
+ "vocab": expl + "</table>",
+ });
+ tx.send_blocking(Ok(format!("<script> add_example({}); </script>\n", serde_json::to_string(&item)?).into_bytes()))?;
+ Ok(())
+ })?;
+
+ tx.send_blocking(Ok(br#"
+ </body>
+ </html>
+ "#.to_vec()))?;
+
+ Ok::<_, anyhow::Error>(())
+ });
Ok(tide::Response::builder(200)
- .body(buf)
+ .body(tide::Body::from_reader(Box::pin(rx).into_async_read(), None))
.content_type(mime::HTML)
.build())
}
@@ -200,14 +277,16 @@ fn calc_example_freq(examples: &[Example]) -> HashMap<char, usize> {
ret
}
-fn gen_examples(
+fn gen_examples<F>(
data: &StateStruct,
allowed_chars: &Charset,
needed_chars: &Charset,
count: usize,
-) -> Vec<Example> {
+ mut callback: F,
+) -> Result<()>
+where F: FnMut(Example) -> Result<()> {
let mut rng = thread_rng();
- let mut ret = vec![];
+ let mut generated = 0;
let mut candidates = data
.examples
@@ -219,7 +298,7 @@ fn gen_examples(
let mut have_chars = Charset::new("");
println!("Ex\tMinCnt\tChars\tNeeded\tAllowed\tCandidates\tChars");
- while ret.len() < count {
+ while generated < count {
let mut selection = None;
let mut total_weight = 0f64;
@@ -245,11 +324,11 @@ fn gen_examples(
let (ex, _) = candidates.remove(i);
remaining_needed = remaining_needed.diff(&ex.chars);
have_chars = have_chars.union(&ex.chars);
- ret.push(ex.clone());
+ generated += 1;
println!(
"{}\t{}\t{}\t{}\t{}\t{}\t{}",
- ret.len(),
+ generated,
f,
have_chars.len(),
remaining_needed.len(),
@@ -257,10 +336,12 @@ fn gen_examples(
counted,
ex.chars.to_string()
);
+
+ callback(ex.clone())?;
} else {
break;
}
}
- ret
+ Ok(())
}