|
1 | 1 | use anyhow::{anyhow, Result};
|
2 | 2 | use lazy_static::lazy_static;
|
3 |
| -use metacall::{loaders, metacall, MetacallNull}; |
4 |
| -use std::{collections::HashMap, ffi::OsStr, marker::Sized, path::Path, sync::Mutex}; |
| 3 | +use metacall::{loaders, metacall, MetacallFuture, MetacallValue}; |
| 4 | +use metassr_utils::checker::CheckerState; |
| 5 | +use std::{ |
| 6 | + collections::HashMap, |
| 7 | + ffi::OsStr, |
| 8 | + marker::Sized, |
| 9 | + path::Path, |
| 10 | + sync::{Arc, Condvar, Mutex}, |
| 11 | +}; |
| 12 | +use tracing::error; |
5 | 13 |
|
6 | 14 | lazy_static! {
|
7 |
| - static ref IS_BUNDLING_SCRIPT_LOADED: Mutex<BundleSciptLoadingState> = |
8 |
| - Mutex::new(BundleSciptLoadingState::new()); |
| 15 | + /// A detector for if the bundling script `./bundle.js` is loaded or not. It is used to solve multiple loading script error in metacall. |
| 16 | + static ref IS_BUNDLING_SCRIPT_LOADED: Mutex<CheckerState> = Mutex::new(CheckerState::new()); |
| 17 | + |
| 18 | + /// A simple checker to check if the bundling function is done or not. It is used to block the program until bundling done. |
| 19 | + static ref IS_COMPLIATION_WAIT: Arc<CompilationWait> = Arc::new(CompilationWait::default()); |
9 | 20 | }
|
10 | 21 | static BUILD_SCRIPT: &str = include_str!("./bundle.js");
|
11 | 22 | const BUNDLING_FUNC: &str = "web_bundling";
|
12 | 23 |
|
13 |
| -/// A detector for if the bundling script `./bundle.js` is loaded or not. |
14 |
| -#[derive(Debug)] |
15 |
| -pub struct BundleSciptLoadingState(bool); |
16 |
| - |
17 |
| -impl BundleSciptLoadingState { |
18 |
| - pub fn new() -> Self { |
19 |
| - Self(false) |
20 |
| - } |
21 |
| - pub fn loaded(&mut self) { |
22 |
| - self.0 = true |
23 |
| - } |
24 |
| - pub fn is_loaded(&self) -> bool { |
25 |
| - self.0 |
26 |
| - } |
| 24 | +/// A simple struct for compilation wait of the bundling function. |
| 25 | +struct CompilationWait { |
| 26 | + checker: Mutex<CheckerState>, |
| 27 | + cond: Condvar, |
27 | 28 | }
|
28 | 29 |
|
29 |
| -impl Default for BundleSciptLoadingState { |
| 30 | +impl Default for CompilationWait { |
30 | 31 | fn default() -> Self {
|
31 |
| - Self::new() |
| 32 | + Self { |
| 33 | + checker: Mutex::new(CheckerState::with(false)), |
| 34 | + cond: Condvar::new(), |
| 35 | + } |
32 | 36 | }
|
33 | 37 | }
|
34 | 38 |
|
@@ -56,24 +60,56 @@ impl<'a> WebBundler<'a> {
|
56 | 60 | }
|
57 | 61 | pub fn exec(&self) -> Result<()> {
|
58 | 62 | let mut guard = IS_BUNDLING_SCRIPT_LOADED.lock().unwrap();
|
59 |
| - if !guard.is_loaded() { |
| 63 | + if !guard.is_true() { |
60 | 64 | if let Err(e) = loaders::from_memory("node", BUILD_SCRIPT) {
|
61 | 65 | return Err(anyhow!("Cannot load bundling script: {e:?}"));
|
62 | 66 | }
|
63 |
| - guard.loaded(); |
| 67 | + guard.make_true(); |
64 | 68 | }
|
65 | 69 | drop(guard);
|
66 |
| - |
67 |
| - if let Err(e) = metacall::<MetacallNull>( |
| 70 | + |
| 71 | + fn resolve(_: Box<dyn MetacallValue>, _: Box<dyn MetacallValue>) { |
| 72 | + let compilation_wait = &*Arc::clone(&IS_COMPLIATION_WAIT); |
| 73 | + let mut started = compilation_wait.checker.lock().unwrap(); |
| 74 | + |
| 75 | + started.make_true(); |
| 76 | + // We notify the condvar that the value has changed |
| 77 | + compilation_wait.cond.notify_one(); |
| 78 | + } |
| 79 | + |
| 80 | + fn reject(err: Box<dyn MetacallValue>, _: Box<dyn MetacallValue>) { |
| 81 | + let compilation_wait = &*Arc::clone(&IS_COMPLIATION_WAIT); |
| 82 | + let mut started = compilation_wait.checker.lock().unwrap(); |
| 83 | + |
| 84 | + error!("Bundling rejected: {err:?}"); |
| 85 | + |
| 86 | + started.make_true(); |
| 87 | + // We notify the condvar that the value has changed |
| 88 | + compilation_wait.cond.notify_one(); |
| 89 | + } |
| 90 | + |
| 91 | + let future = metacall::<MetacallFuture>( |
68 | 92 | BUNDLING_FUNC,
|
69 | 93 | [
|
70 | 94 | serde_json::to_string(&self.targets)?,
|
71 | 95 | self.dist_path.to_str().unwrap().to_owned(),
|
72 | 96 | ],
|
73 |
| - ) { |
74 |
| - return Err(anyhow!("Cannot running {BUNDLING_FUNC}(): {e:?}")); |
| 97 | + ) |
| 98 | + .unwrap(); |
| 99 | + |
| 100 | + future.then(resolve).catch(reject).await_fut(); |
| 101 | + |
| 102 | + // Wait for the thread to start up. |
| 103 | + let compilation_wait = Arc::clone(&IS_COMPLIATION_WAIT); |
| 104 | + |
| 105 | + let mut started = compilation_wait.checker.lock().unwrap(); |
| 106 | + |
| 107 | + // Waiting till future done |
| 108 | + while !started.is_true() { |
| 109 | + started = Arc::clone(&IS_COMPLIATION_WAIT).cond.wait(started).unwrap(); |
75 | 110 | }
|
76 |
| - |
| 111 | + // Reset checker |
| 112 | + started.make_false(); |
77 | 113 | Ok(())
|
78 | 114 | }
|
79 | 115 | }
|
|
0 commit comments