Finish web implementation to enable hosting on janbergen.de

This commit is contained in:
Jan Bergen 2024-06-04 20:58:58 +02:00
parent 521113cd7c
commit 86416e3566
7 changed files with 300 additions and 13 deletions

View File

@ -460,9 +460,11 @@ dependencies = [
"egui_extras", "egui_extras",
"egui_plot", "egui_plot",
"gauss-quad", "gauss-quad",
"gloo-net",
"indicatif", "indicatif",
"nohash-hasher", "nohash-hasher",
"num", "num",
"wasm-bindgen-futures",
] ]
[[package]] [[package]]
@ -1251,6 +1253,12 @@ dependencies = [
"miniz_oxide", "miniz_oxide",
] ]
[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]] [[package]]
name = "foreign-types" name = "foreign-types"
version = "0.5.0" version = "0.5.0"
@ -1287,6 +1295,15 @@ dependencies = [
"percent-encoding", "percent-encoding",
] ]
[[package]]
name = "futures-channel"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
dependencies = [
"futures-core",
]
[[package]] [[package]]
name = "futures-core" name = "futures-core"
version = "0.3.30" version = "0.3.30"
@ -1406,6 +1423,40 @@ dependencies = [
"xml-rs", "xml-rs",
] ]
[[package]]
name = "gloo-net"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43aaa242d1239a8822c15c645f02166398da4f8b5c4bae795c1f5b44e9eee173"
dependencies = [
"futures-channel",
"futures-core",
"futures-sink",
"gloo-utils",
"http",
"js-sys",
"pin-project",
"serde",
"serde_json",
"thiserror",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
]
[[package]]
name = "gloo-utils"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b5555354113b18c547c1d3a98fbf7fb32a9ff4f6fa112ce823a21641a0ba3aa"
dependencies = [
"js-sys",
"serde",
"serde_json",
"wasm-bindgen",
"web-sys",
]
[[package]] [[package]]
name = "glow" name = "glow"
version = "0.13.1" version = "0.13.1"
@ -1587,6 +1638,17 @@ dependencies = [
"windows-sys 0.52.0", "windows-sys 0.52.0",
] ]
[[package]]
name = "http"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1"
dependencies = [
"bytes",
"fnv",
"itoa",
]
[[package]] [[package]]
name = "icrate" name = "icrate"
version = "0.0.4" version = "0.0.4"
@ -1664,6 +1726,12 @@ dependencies = [
"windows-sys 0.48.0", "windows-sys 0.48.0",
] ]
[[package]]
name = "itoa"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
[[package]] [[package]]
name = "jni" name = "jni"
version = "0.21.1" version = "0.21.1"
@ -2280,6 +2348,26 @@ version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
[[package]]
name = "pin-project"
version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3"
dependencies = [
"pin-project-internal",
]
[[package]]
name = "pin-project-internal"
version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.60",
]
[[package]] [[package]]
name = "pin-project-lite" name = "pin-project-lite"
version = "0.2.14" version = "0.2.14"
@ -2566,6 +2654,12 @@ dependencies = [
"windows-sys 0.52.0", "windows-sys 0.52.0",
] ]
[[package]]
name = "ryu"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
[[package]] [[package]]
name = "safe_arch" name = "safe_arch"
version = "0.7.1" version = "0.7.1"
@ -2629,6 +2723,17 @@ dependencies = [
"syn 2.0.60", "syn 2.0.60",
] ]
[[package]]
name = "serde_json"
version = "1.0.117"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]] [[package]]
name = "serde_repr" name = "serde_repr"
version = "0.1.19" version = "0.1.19"

View File

@ -15,8 +15,15 @@ egui_plot = "0.27.2"
indicatif = "0.17.8" indicatif = "0.17.8"
nohash-hasher = "0.2.0" nohash-hasher = "0.2.0"
[target.'cfg(target_arch = "wasm32")'.dependencies]
wasm-bindgen-futures = "0.4"
gloo-net = "0.5.0"
[profile.release] [profile.release]
debug = true debug = true
# lto = "fat" # lto = "fat"
# codegen-units = 1 # codegen-units = 1
[profile.webrelease]
inherits = "release"
opt-level = "s"

3
bachelorarbeit/build.sh Normal file
View File

@ -0,0 +1,3 @@
cargo build --target wasm32-unknown-unknown --profile webrelease
mkdir ./target/web-out
wasm-bindgen ./target/wasm32-unknown-unknown/webrelease/app_bg.wasm --out-name app --out-dir ./target/web-out/ --target web --no-typescript

127
bachelorarbeit/index.html Normal file
View File

@ -0,0 +1,127 @@
<!DOCTYPE html>
<html>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<!-- Disable zooming: -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<head>
<!-- change this to your project name -->
<title>eframe template</title>
<!-- config for our rust wasm binary. go to https://trunkrs.dev/assets/#rust for more customization -->
<link data-trunk rel="rust" data-wasm-opt="2" />
<!-- this is the base url relative to which other urls will be constructed. trunk will insert this from the public-url option -->
<base data-trunk-public-url />
<meta name="theme-color" media="(prefers-color-scheme: light)" content="white">
<meta name="theme-color" media="(prefers-color-scheme: dark)" content="#404040">
<style>
html {
/* Remove touch delay: */
touch-action: manipulation;
}
body {
/* Light mode background color for what is not covered by the egui canvas,
or where the egui canvas is translucent. */
background: #909090;
}
@media (prefers-color-scheme: dark) {
body {
/* Dark mode background color for what is not covered by the egui canvas,
or where the egui canvas is translucent. */
background: #404040;
}
}
/* Allow canvas to fill entire web page: */
html,
body {
overflow: hidden;
margin: 0 !important;
padding: 0 !important;
height: 100%;
width: 100%;
}
/* Position canvas in center-top: */
canvas {
margin-right: auto;
margin-left: auto;
display: block;
position: absolute;
top: 0%;
left: 50%;
transform: translate(-50%, 0%);
}
.centered {
margin-right: auto;
margin-left: auto;
display: block;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: #f0f0f0;
font-size: 24px;
font-family: Ubuntu-Light, Helvetica, sans-serif;
text-align: center;
}
/* ---------------------------------------------- */
/* Loading animation from https://loading.io/css/ */
.lds-dual-ring {
display: inline-block;
width: 24px;
height: 24px;
}
.lds-dual-ring:after {
content: " ";
display: block;
width: 24px;
height: 24px;
margin: 0px;
border-radius: 50%;
border: 3px solid #fff;
border-color: #fff transparent #fff transparent;
animation: lds-dual-ring 1.2s linear infinite;
}
@keyframes lds-dual-ring {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
</style>
<script type="module">
import init from '/app.js';
const wasm = fetch('/app_bg.wasm');
window.onload = () => {
init(wasm);
}
</script>
</head>
<body>
<!-- The WASM code will resize the canvas dynamically -->
<!-- the id is hardcoded in main.rs . so, make sure both match. -->
<canvas id="morellus_canvas_id"></canvas>
</body>
</html>
<!-- Powered by egui: https://github.com/emilk/egui/ -->

View File

@ -6,6 +6,11 @@ use std::collections::HashMap;
use std::io; use std::io;
use std::rc::Rc; use std::rc::Rc;
use std::{
fs::File,
io::BufReader,
};
use crate::gq_storage; // This should be moved to main.rs after new archtitecture (see main.rs TODO) use crate::gq_storage; // This should be moved to main.rs after new archtitecture (see main.rs TODO)
pub type Complex = num::complex::Complex<f64>; pub type Complex = num::complex::Complex<f64>;
@ -32,8 +37,21 @@ pub struct Cache {
impl Cache { impl Cache {
pub fn from_file(filepath: &str) -> io::Result<Cache> { pub fn from_file(filepath: &str) -> io::Result<Cache> {
let file = File::open(filepath)?;
let mut file = BufReader::new(file);
let me = Cache{ let me = Cache{
gauss_quad_lut: gq_storage::deserialize(filepath, |_| true)?.into_iter() gauss_quad_lut: gq_storage::deserialize(&mut file, |_| true)?.into_iter()
.map(|(roots, weights)| (u32::try_from(roots.len()).unwrap(), (Rc::from(roots), Rc::from(weights)))).collect(),
delta_lut: HashMap::with_hasher(Default::default()),
omnes_lut: HashMap::with_hasher(Default::default())
};
Ok(me)
}
pub fn from_slice(data: &[u8]) -> io::Result<Cache> {
let mut cursor = std::io::Cursor::new(data);
let me = Cache{
gauss_quad_lut: gq_storage::deserialize(&mut cursor, |_| true)?.into_iter()
.map(|(roots, weights)| (u32::try_from(roots.len()).unwrap(), (Rc::from(roots), Rc::from(weights)))).collect(), .map(|(roots, weights)| (u32::try_from(roots.len()).unwrap(), (Rc::from(roots), Rc::from(weights)))).collect(),
delta_lut: HashMap::with_hasher(Default::default()), delta_lut: HashMap::with_hasher(Default::default()),
omnes_lut: HashMap::with_hasher(Default::default()) omnes_lut: HashMap::with_hasher(Default::default())

View File

@ -28,15 +28,12 @@ pub fn serialize(filepath: &str, params: Vec<(Vec<f64>, Vec<f64>)>) -> io::Resul
Ok(()) Ok(())
} }
pub fn deserialize(filepath: &str, filter: impl Fn(u64) -> bool) -> io::Result<Vec<(Vec<f64>, Vec<f64>)>> { pub fn deserialize<R:std::io::Read + std::io::Seek>(reader: &mut R, filter: impl Fn(u64) -> bool) -> io::Result<Vec<(Vec<f64>, Vec<f64>)>> {
let file = File::open(filepath)?;
let mut file = BufReader::new(file);
let mut buf = [0u8; 8]; let mut buf = [0u8; 8];
let mut values = Vec::new(); let mut values = Vec::new();
'outer: loop { 'outer: loop {
let res = file.read(&mut buf)?; let res = reader.read(&mut buf)?;
if res < 8 { if res < 8 {
break; break;
} }
@ -44,7 +41,7 @@ pub fn deserialize(filepath: &str, filter: impl Fn(u64) -> bool) -> io::Result<V
// skips stored floats for n that should not be stored // skips stored floats for n that should not be stored
if !filter(n) { if !filter(n) {
file.seek(SeekFrom::Current(i64::try_from(2*n*8).unwrap())).unwrap(); reader.seek(SeekFrom::Current(i64::try_from(2*n*8).unwrap())).unwrap();
continue; continue;
} }
@ -52,7 +49,7 @@ pub fn deserialize(filepath: &str, filter: impl Fn(u64) -> bool) -> io::Result<V
let mut roots = Vec::new(); let mut roots = Vec::new();
for _ in 0..n { for _ in 0..n {
let res = file.read(&mut buf)?; let res = reader.read(&mut buf)?;
if res < 8 { if res < 8 {
break 'outer; break 'outer;
} }
@ -61,7 +58,7 @@ pub fn deserialize(filepath: &str, filter: impl Fn(u64) -> bool) -> io::Result<V
let mut weights = Vec::new(); let mut weights = Vec::new();
for _ in 0..n { for _ in 0..n {
let res = file.read(&mut buf)?; let res = reader.read(&mut buf)?;
if res < 8 { if res < 8 {
break 'outer; break 'outer;
} }
@ -72,13 +69,16 @@ pub fn deserialize(filepath: &str, filter: impl Fn(u64) -> bool) -> io::Result<V
Ok(values) Ok(values)
} }
pub fn fill_with_gauss_quad(n_values: Vec<u64>) { pub fn fill_with_gauss_quad(n_values: Vec<u64>) -> std::io::Result<()> {
let mut params = Vec::new(); let mut params = Vec::new();
for i in n_values { for i in n_values {
let gq = GaussLegendre::init(usize::try_from(i).unwrap()); let gq = GaussLegendre::init(usize::try_from(i).unwrap());
params.push((gq.nodes, gq.weights)); params.push((gq.nodes, gq.weights));
} }
serialize("./gauss_quad_lut.morello", params).unwrap(); serialize("./gauss_quad_lut.morello", params).unwrap();
let res = deserialize("./gauss_quad_lut.morello", |_| true); let file = File::open("./gauss_quad_lut.morello")?;
let mut file = BufReader::new(file);
let res = deserialize(&mut file, |_| true);
println!("{:?}", res); println!("{:?}", res);
Ok(())
} }

View File

@ -119,7 +119,7 @@ impl eframe::App for App {
ui.label("You can calculate the following functions:"); ui.label("You can calculate the following functions:");
ui.horizontal(|ui| { ui.with_layout(egui::Layout::left_to_right(egui::Align::Center), |ui| {
for i in 0..self.plots_available.len() { for i in 0..self.plots_available.len() {
let button = ui.button( format!("{}", self.plots_available[i].clone())); let button = ui.button( format!("{}", self.plots_available[i].clone()));
if button.clicked() { if button.clicked() {
@ -257,6 +257,7 @@ impl eframe::App for App {
} }
} }
#[cfg(not(target_arch = "wasm32"))]
fn main() { fn main() {
let mut app = App::default(); let mut app = App::default();
app.calc_cache = calc::Cache::from_file("./gauss_quad_lut.morello").unwrap(); app.calc_cache = calc::Cache::from_file("./gauss_quad_lut.morello").unwrap();
@ -266,9 +267,35 @@ fn main() {
// std::hint::black_box(&y_values_phi0); // std::hint::black_box(&y_values_phi0);
// println!("{:?}", t0.elapsed()); // println!("{:?}", t0.elapsed());
eframe::run_native("Morellus", eframe::NativeOptions::default(), Box::new(|_cc| Box::new(app))).unwrap(); eframe::run_native("Morellus", eframe::NativeOptions::default(), Box::new(|_cc| Box::new(app))).unwrap();
} }
#[cfg(target_arch = "wasm32")]
fn main() {
let mut app = App::default();
wasm_bindgen_futures::spawn_local(async {
let res = gloo_net::http::RequestBuilder::new("/lut/gauss_quad_lut.morello")
.method(gloo_net::http::Method::POST)
.send()
.await
.unwrap();
app.calc_cache = calc::Cache::from_slice(&res.binary().await.unwrap()).unwrap();
let web_options = eframe::WebOptions::default();
eframe::WebRunner::new()
.start(
"morellus_canvas_id",
web_options,
Box::new(|_cc| Box::new(app)),
)
.await
.expect("failed to start eframe");
});
}
fn log_map(x:f64) -> f64 { fn log_map(x:f64) -> f64 {
x.floor() + (1.0 + (x - x.floor()) * 10.0).log10() x.floor() + (1.0 + (x - x.floor()) * 10.0).log10()
} }