Skip to content

Commit 13950d2

Browse files
committed
refactor: clean up code, prevent freezing in the sim
probably some other stuff in here too... lesson to self: make smaller commits
1 parent 20d3616 commit 13950d2

File tree

12 files changed

+283
-127
lines changed

12 files changed

+283
-127
lines changed

Sources/Code/TypeScript/Components/NavigraphLogin.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,13 @@ export class NavigraphLogin extends DisplayComponent<NavigraphLoginProps> {
2929
console.info("WASM downloaded navdata")
3030
this.navdataTextRef.instance.textContent = "Navdata downloaded!"
3131
})
32+
33+
this.commBusListener.on("UnzippedFilesRemaining", (jsonArgs: string) => {
34+
const args = JSON.parse(jsonArgs)
35+
console.info("WASM unzipping files", args)
36+
const percent = Math.round((args.unzipped / args.total) * 100)
37+
this.navdataTextRef.instance.textContent = `Unzipping files... ${percent}% complete`
38+
})
3239
}
3340

3441
public render(): VNode {
Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,2 @@
1-
[target.wasm32-wasi]
2-
rustflags = [
3-
"-Clink-arg=--export-table",
4-
"-Clink-arg=--export=malloc",
5-
"-Clink-arg=--export=free",
6-
]
7-
81
[build]
92
target = "wasm32-wasi"

Sources/Code/WASM/navdata_updater/Cargo.toml

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,5 @@ strip = true
1717
msfs = { git = "https://github.com/pepperoni505/msfs-rs.git", branch = "main" }
1818
serde = "1.0.190"
1919
serde_json = "1.0.108"
20-
rusqlite = { git = "https://github.com/rusqlite/rusqlite", rev = "d7ac6a1", features = ["bundled", "wasm32-wasi-vfs"] }
21-
zip = { version = "0.6.4", default-features = false, features = ["deflate"] }
22-
23-
[patch.crates-io]
24-
libsqlite3-sys = { git = "https://github.com/navigraph/rusqlite", branch = "master" }
20+
rusqlite = { git = "https://github.com/navigraph/rusqlite", rev = "366c520", features = ["bundled", "wasm32-wasi-vfs"] }
21+
zip = { version = "0.6.4", default-features = false, features = ["deflate"] }
Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,2 @@
1-
@echo off
2-
3-
set "CLANG_LIB_WASI=%WASI_SDK%\\lib\\clang\\15.0.7\\lib\\wasi"
4-
set "WASI_SYSROOT=%WASI_SDK%\\share\\wasi-sysroot"
5-
set "CC=%WASI_SDK%\\bin\\clang --sysroot=%WASI_SYSROOT%"
6-
set "AR=%WASI_SDK%\\bin\\llvm-ar"
7-
set "CC_wasm32_wasi=%WASI_SDK%\\bin\\clang"
8-
set "LIBSQLITE3_FLAGS=-DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_SHARED_CACHE -D_LARGEFILE64_SOURCE"
9-
set "RUSTFLAGS=-Clink-arg=--export-table -Clink-arg=--export=malloc -Clink-arg=--export=free -Clink-arg=-L%CLANG_LIB_WASI% -Clink-arg=-lclang_rt.builtins-wasm32"
10-
11-
12-
cargo build --release
1+
call run_cargo_cmd.bat build --release
132
copy "target\wasm32-wasi\release\navdata_updater.wasm" "..\..\..\..\PackageSources\SimObjects\Airplanes\Navigraph_Navdata_Updater_Aircraft\panel\navdata_updater.wasm"
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
@echo off
2+
3+
set "CLANG_LIB_WASI=%WASI_SDK%\\lib\\clang\\15.0.7\\lib\\wasi"
4+
set "WASI_SYSROOT=%WASI_SDK%\\share\\wasi-sysroot"
5+
set "CC=%WASI_SDK%\\bin\\clang --sysroot=%WASI_SYSROOT%"
6+
set "AR=%WASI_SDK%\\bin\\llvm-ar"
7+
set "CC_wasm32_wasi=%WASI_SDK%\\bin\\clang"
8+
set "LIBSQLITE3_FLAGS=-DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_SHARED_CACHE -D_LARGEFILE64_SOURCE"
9+
set "RUSTFLAGS=-Clink-arg=-L%CLANG_LIB_WASI% -Clink-arg=-lclang_rt.builtins-wasm32 -Clink-arg=--export-table -Clink-arg=--export=malloc -Clink-arg=--export=free"
10+
11+
12+
:: Run the Cargo command passed as an argument
13+
if "%1"=="" (
14+
echo No Cargo command specified.
15+
) else (
16+
cargo %*
17+
)
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
use std::collections::HashMap;
2+
use std::mem;
3+
use std::rc::Rc;
4+
5+
use crate::download::downloader::NavdataDownloader;
6+
use msfs::{commbus::*, MSFSEvent};
7+
8+
pub struct Dispatcher<'a> {
9+
commbus: Option<CommBus<'a>>,
10+
downloader: Rc<NavdataDownloader>,
11+
}
12+
13+
impl<'a> Dispatcher<'a> {
14+
pub fn new() -> Self {
15+
Dispatcher {
16+
commbus: None,
17+
downloader: Rc::new(NavdataDownloader::new()),
18+
}
19+
}
20+
21+
pub fn on_msfs_event(&mut self, event: MSFSEvent) {
22+
match event {
23+
MSFSEvent::PostInitialize => {
24+
self.handle_initialized();
25+
}
26+
MSFSEvent::PostUpdate => {
27+
self.handle_update();
28+
}
29+
MSFSEvent::PreKill => {
30+
// handle pre kill TODO wait for the unregister functions to be ported
31+
}
32+
33+
_ => {}
34+
}
35+
}
36+
37+
fn handle_initialized(&mut self) {
38+
println!("[WASM] Initialized");
39+
let captured_downloader = self.downloader.clone();
40+
self.commbus = CommBus::register("DownloadNavdata", move |args| {
41+
captured_downloader.download(args)
42+
});
43+
}
44+
45+
fn handle_update(&mut self) {
46+
// update unzip
47+
// todo: maybe another way to check instead of cloning? i mean we drop the value anyway but not sure on performance
48+
let captured_downloader = self.downloader.clone();
49+
if captured_downloader.get_files_to_unzip() > 0 {
50+
let total_files = captured_downloader.get_total_files();
51+
let files_unzipped = captured_downloader.get_files_unzipped();
52+
let mut map = HashMap::new();
53+
map.insert("total", total_files);
54+
map.insert("unzipped", files_unzipped);
55+
let data = serde_json::to_string(&map).unwrap();
56+
// this is temporary until msfs-rs handles this unsafe stuff (soon TM)
57+
let i8_slice: &[i8] = unsafe { mem::transmute(data.as_bytes()) };
58+
println!(
59+
"[WASM] total: {}, unzipped: {}",
60+
total_files, files_unzipped
61+
);
62+
// only send the call if unzipped is divisible by 100 (kinda hacky but otherwise we flood the commbus (not good!))
63+
if files_unzipped % 100 == 0 {
64+
CommBus::call(
65+
"UnzippedFilesRemaining",
66+
i8_slice,
67+
CommBusBroadcastFlags::JS,
68+
);
69+
}
70+
let has_more_files = captured_downloader.unzip_batch(10);
71+
if !has_more_files {
72+
println!("[WASM] finished unzip");
73+
CommBus::call("NavdataDownloaded", &[], CommBusBroadcastFlags::JS);
74+
}
75+
}
76+
}
77+
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
use std::cell::RefCell;
2+
use std::fs;
3+
use std::io::Cursor;
4+
use std::path::PathBuf;
5+
use std::rc::Rc;
6+
7+
use msfs::network::*;
8+
9+
use crate::download::zip_handler::ZipFileHandler;
10+
use crate::util::JsonParser;
11+
12+
pub struct NavdataDownloader {
13+
zip_handler: RefCell<Option<ZipFileHandler<Cursor<Vec<u8>>>>>,
14+
}
15+
16+
impl NavdataDownloader {
17+
pub fn new() -> Self {
18+
NavdataDownloader {
19+
zip_handler: RefCell::new(None),
20+
}
21+
}
22+
23+
pub fn download(self: &Rc<Self>, args: &[u8]) {
24+
println!("[WASM] call received");
25+
let json_result = JsonParser::parse(args);
26+
if json_result.is_err() {
27+
println!("[WASM] json error: {}", json_result.err().unwrap());
28+
return;
29+
}
30+
let json = json_result.unwrap();
31+
let url = json["url"].as_str().unwrap_or_default();
32+
33+
let captured_self = self.clone();
34+
NetworkRequestBuilder::new(url)
35+
.unwrap()
36+
.with_callback(move |request, status_code| {
37+
captured_self.request_finished_callback(request, status_code)
38+
})
39+
.get()
40+
.unwrap();
41+
}
42+
43+
fn request_finished_callback(&self, request: NetworkRequest, status_code: i32) {
44+
if status_code != 200 {
45+
println!("[WASM] request failed");
46+
return;
47+
}
48+
let path = PathBuf::from("\\work/navdata");
49+
if let Err(e) = fs::create_dir_all(&path) {
50+
println!("[WASM] directory error: {}", e);
51+
return;
52+
}
53+
54+
let data = request.data().unwrap();
55+
let cursor = Cursor::new(data);
56+
let zip = zip::ZipArchive::new(cursor).unwrap();
57+
58+
let handler = ZipFileHandler::new(zip, path);
59+
let mut zip_handler = self.zip_handler.borrow_mut();
60+
*zip_handler = Some(handler);
61+
}
62+
63+
/// Returns the number of files left to unzip
64+
pub fn get_files_to_unzip(&self) -> usize {
65+
let zip_handler = self.zip_handler.borrow();
66+
match zip_handler.as_ref() {
67+
Some(handler) => handler.zip_file_count - handler.current_file_index,
68+
None => 0,
69+
}
70+
}
71+
72+
/// Returns the total number of files in the zip
73+
pub fn get_total_files(&self) -> usize {
74+
let zip_handler = self.zip_handler.borrow();
75+
match zip_handler.as_ref() {
76+
Some(handler) => handler.zip_file_count,
77+
None => 0,
78+
}
79+
}
80+
81+
/// Returns the number of files that have been unzipped
82+
pub fn get_files_unzipped(&self) -> usize {
83+
let zip_handler = self.zip_handler.borrow();
84+
match zip_handler.as_ref() {
85+
Some(handler) => handler.current_file_index,
86+
None => 0,
87+
}
88+
}
89+
90+
/// Unzips a batch of files
91+
///
92+
/// Returns true if there are more files to unzip (false if we are done)
93+
pub fn unzip_batch(&self, batch_size: usize) -> bool {
94+
let mut zip_handler = self.zip_handler.borrow_mut();
95+
match zip_handler.as_mut() {
96+
Some(handler) => handler.unzip_batch(batch_size),
97+
None => false,
98+
}
99+
}
100+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
pub mod downloader;
2+
pub mod zip_handler;
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
use std::fs;
2+
use std::io;
3+
use std::path::PathBuf;
4+
5+
pub struct ZipFileHandler<R: io::Read + io::Seek> {
6+
pub zip_archive: Option<zip::ZipArchive<R>>,
7+
path_buf: PathBuf,
8+
pub current_file_index: usize,
9+
pub zip_file_count: usize,
10+
}
11+
12+
impl<R: io::Read + io::Seek> ZipFileHandler<R> {
13+
pub fn new(zip_archive: zip::ZipArchive<R>, path_buf: PathBuf) -> Self {
14+
// To make accessing zip archive size easier, we just store it to the struct instead of calling it every time (avoids ownership issues)
15+
let zip_file_count = zip_archive.len();
16+
Self {
17+
zip_archive: Some(zip_archive),
18+
path_buf,
19+
current_file_index: 0,
20+
zip_file_count,
21+
}
22+
}
23+
24+
pub fn unzip_batch(&mut self, batch_size: usize) -> bool {
25+
if self.zip_archive.is_none() {
26+
return false;
27+
}
28+
let unwrapped_zip_archive = self.zip_archive.as_mut().unwrap();
29+
let total_files = unwrapped_zip_archive.len();
30+
for _ in 0..batch_size {
31+
if self.current_file_index >= total_files {
32+
// lets clear our zip
33+
self.zip_archive = None;
34+
return false; // no more files to unzip
35+
}
36+
37+
let mut file = match unwrapped_zip_archive.by_index(self.current_file_index) {
38+
Ok(file) => file,
39+
Err(_) => continue,
40+
};
41+
let outpath = match file.enclosed_name() {
42+
Some(path) => self.path_buf.join(path),
43+
None => continue,
44+
};
45+
46+
if (*file.name()).ends_with('/') {
47+
fs::create_dir_all(outpath).unwrap();
48+
} else {
49+
if let Some(p) = outpath.parent() {
50+
if !p.exists() {
51+
fs::create_dir_all(p).unwrap();
52+
}
53+
}
54+
let mut outfile = fs::File::create(outpath).unwrap();
55+
io::copy(&mut file, &mut outfile).unwrap();
56+
}
57+
self.current_file_index += 1;
58+
}
59+
true
60+
}
61+
}

0 commit comments

Comments
 (0)