|
@@ -1,4 +1,4 @@
|
|
-use crate::{builder::BuildConfig, cli::DevelopOptions, config::Config, error::Result};
|
|
|
|
|
|
+use crate::{builder::BuildConfig, cli::DevelopOptions, config::CrateConfig, error::Result};
|
|
use async_std::prelude::FutureExt;
|
|
use async_std::prelude::FutureExt;
|
|
|
|
|
|
use async_std::future;
|
|
use async_std::future;
|
|
@@ -7,6 +7,8 @@ use async_std::prelude::*;
|
|
use log::info;
|
|
use log::info;
|
|
use notify::{RecommendedWatcher, RecursiveMode, Watcher};
|
|
use notify::{RecommendedWatcher, RecursiveMode, Watcher};
|
|
use std::path::PathBuf;
|
|
use std::path::PathBuf;
|
|
|
|
+use std::sync::atomic::AtomicBool;
|
|
|
|
+use std::sync::Arc;
|
|
use std::time::Duration;
|
|
use std::time::Duration;
|
|
|
|
|
|
pub struct DevelopConfig {}
|
|
pub struct DevelopConfig {}
|
|
@@ -16,15 +18,20 @@ impl Into<DevelopConfig> for DevelopOptions {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-pub async fn start(config: &Config, _options: &DevelopConfig) -> Result<()> {
|
|
|
|
|
|
+type ErrStatus = Arc<AtomicBool>;
|
|
|
|
+
|
|
|
|
+pub async fn start(config: &CrateConfig, _options: &DevelopConfig) -> Result<()> {
|
|
log::info!("Starting development server 🚀");
|
|
log::info!("Starting development server 🚀");
|
|
|
|
|
|
- let Config { out_dir, .. } = config;
|
|
|
|
|
|
+ let CrateConfig { out_dir, .. } = config;
|
|
|
|
+
|
|
|
|
+ let is_err = Arc::new(AtomicBool::new(false));
|
|
|
|
|
|
// Spawn the server onto a seperate task
|
|
// Spawn the server onto a seperate task
|
|
// This lets the task progress while we handle file updates
|
|
// This lets the task progress while we handle file updates
|
|
- let server = async_std::task::spawn(launch_server(out_dir.clone()));
|
|
|
|
- let watcher = async_std::task::spawn(watch_directory(config.clone()));
|
|
|
|
|
|
+ let server = async_std::task::spawn(launch_server(out_dir.clone(), is_err.clone()));
|
|
|
|
+
|
|
|
|
+ let watcher = async_std::task::spawn(watch_directory(config.clone(), is_err.clone()));
|
|
|
|
|
|
match server.race(watcher).await {
|
|
match server.race(watcher).await {
|
|
Err(e) => log::warn!("Error running development server, {:?}", e),
|
|
Err(e) => log::warn!("Error running development server, {:?}", e),
|
|
@@ -34,14 +41,19 @@ pub async fn start(config: &Config, _options: &DevelopConfig) -> Result<()> {
|
|
Ok(())
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
|
|
-async fn watch_directory(config: Config) -> Result<()> {
|
|
|
|
|
|
+async fn watch_directory(config: CrateConfig, is_err: ErrStatus) -> Result<()> {
|
|
// Create a channel to receive the events.
|
|
// Create a channel to receive the events.
|
|
let (watcher_tx, watcher_rx) = async_std::channel::bounded(100);
|
|
let (watcher_tx, watcher_rx) = async_std::channel::bounded(100);
|
|
|
|
|
|
// Automatically select the best implementation for your platform.
|
|
// Automatically select the best implementation for your platform.
|
|
// You can also access each implementation directly e.g. INotifyWatcher.
|
|
// You can also access each implementation directly e.g. INotifyWatcher.
|
|
let mut watcher: RecommendedWatcher = Watcher::new(move |res| {
|
|
let mut watcher: RecommendedWatcher = Watcher::new(move |res| {
|
|
|
|
+<<<<<<< HEAD
|
|
async_std::task::block_on(watcher_tx.send(res));
|
|
async_std::task::block_on(watcher_tx.send(res));
|
|
|
|
+=======
|
|
|
|
+ // send an event
|
|
|
|
+ let _ = async_std::task::block_on(watcher_tx.send(res));
|
|
|
|
+>>>>>>> 9451713 (wip: studio upgrades)
|
|
})
|
|
})
|
|
.expect("failed to make watcher");
|
|
.expect("failed to make watcher");
|
|
|
|
|
|
@@ -53,44 +65,63 @@ async fn watch_directory(config: Config) -> Result<()> {
|
|
.watch(&src_dir.join("src"), RecursiveMode::Recursive)
|
|
.watch(&src_dir.join("src"), RecursiveMode::Recursive)
|
|
.expect("Failed to watch dir");
|
|
.expect("Failed to watch dir");
|
|
|
|
|
|
- watcher
|
|
|
|
- .watch(&src_dir.join("examples"), RecursiveMode::Recursive)
|
|
|
|
- .expect("Failed to watch dir");
|
|
|
|
|
|
+ match watcher.watch(&src_dir.join("examples"), RecursiveMode::Recursive) {
|
|
|
|
+ Ok(_) => {}
|
|
|
|
+ Err(e) => log::warn!("Failed to watch examples dir, {:?}", e),
|
|
|
|
+ }
|
|
|
|
|
|
let build_config = BuildConfig::default();
|
|
let build_config = BuildConfig::default();
|
|
|
|
|
|
'run: loop {
|
|
'run: loop {
|
|
- crate::builder::build(&config, &build_config)?;
|
|
|
|
-
|
|
|
|
- // Wait for the message with a debounce
|
|
|
|
- let _msg = watcher_rx
|
|
|
|
- .recv()
|
|
|
|
- .join(future::ready(1_usize).delay(Duration::from_millis(2000)))
|
|
|
|
- .await;
|
|
|
|
|
|
+ match crate::builder::build(&config, &build_config) {
|
|
|
|
+ Ok(_) => {
|
|
|
|
+ is_err.store(false, std::sync::atomic::Ordering::Relaxed);
|
|
|
|
+ async_std::task::sleep(std::time::Duration::from_millis(500)).await;
|
|
|
|
+ }
|
|
|
|
+ Err(err) => is_err.store(true, std::sync::atomic::Ordering::Relaxed),
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ let mut msg = None;
|
|
|
|
+ loop {
|
|
|
|
+ let new_msg = watcher_rx.recv().await.unwrap().unwrap();
|
|
|
|
+ if !watcher_rx.is_empty() {
|
|
|
|
+ msg = Some(new_msg);
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
info!("File updated, rebuilding app");
|
|
info!("File updated, rebuilding app");
|
|
}
|
|
}
|
|
Ok(())
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
|
|
-async fn launch_server(outdir: PathBuf) -> Result<()> {
|
|
|
|
|
|
+async fn launch_server(outdir: PathBuf, is_err: ErrStatus) -> Result<()> {
|
|
let _crate_dir = crate::cargo::crate_root()?;
|
|
let _crate_dir = crate::cargo::crate_root()?;
|
|
let _workspace_dir = crate::cargo::workspace_root()?;
|
|
let _workspace_dir = crate::cargo::workspace_root()?;
|
|
|
|
|
|
- let mut app = tide::with_state(ServerState::new(outdir.to_owned()));
|
|
|
|
|
|
+ let mut app = tide::with_state(ServerState::new(outdir.to_owned(), is_err));
|
|
let p = outdir.display().to_string();
|
|
let p = outdir.display().to_string();
|
|
|
|
|
|
app.at("/")
|
|
app.at("/")
|
|
.get(|req: tide::Request<ServerState>| async move {
|
|
.get(|req: tide::Request<ServerState>| async move {
|
|
log::info!("Connected to development server");
|
|
log::info!("Connected to development server");
|
|
let state = req.state();
|
|
let state = req.state();
|
|
- Ok(tide::Body::from_file(state.serv_path.clone().join("index.html")).await?)
|
|
|
|
|
|
+
|
|
|
|
+ match state.is_err.load(std::sync::atomic::Ordering::Relaxed) {
|
|
|
|
+ true => Ok(tide::Body::from_string(format!(
|
|
|
|
+ include_str!("./err.html"),
|
|
|
|
+ err = "_"
|
|
|
|
+ ))),
|
|
|
|
+ false => {
|
|
|
|
+ Ok(tide::Body::from_file(state.serv_path.clone().join("index.html")).await?)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
})
|
|
})
|
|
.serve_dir(p)?;
|
|
.serve_dir(p)?;
|
|
|
|
|
|
let port = "8080";
|
|
let port = "8080";
|
|
- let serve_addr = format!("0.0.0.0:{}", port);
|
|
|
|
- // let serve_addr = format!("127.0.0.1:{}", port);
|
|
|
|
|
|
+ // let serve_addr = format!("0.0.0.0:{}", port);
|
|
|
|
+ let serve_addr = format!("127.0.0.1:{}", port);
|
|
|
|
|
|
info!("App available at http://{}", serve_addr);
|
|
info!("App available at http://{}", serve_addr);
|
|
app.listen(serve_addr).await?;
|
|
app.listen(serve_addr).await?;
|
|
@@ -103,9 +134,10 @@ async fn launch_server(outdir: PathBuf) -> Result<()> {
|
|
#[derive(Clone)]
|
|
#[derive(Clone)]
|
|
struct ServerState {
|
|
struct ServerState {
|
|
serv_path: PathBuf,
|
|
serv_path: PathBuf,
|
|
|
|
+ is_err: ErrStatus,
|
|
}
|
|
}
|
|
impl ServerState {
|
|
impl ServerState {
|
|
- fn new(serv_path: PathBuf) -> Self {
|
|
|
|
- Self { serv_path }
|
|
|
|
|
|
+ fn new(serv_path: PathBuf, is_err: ErrStatus) -> Self {
|
|
|
|
+ Self { serv_path, is_err }
|
|
}
|
|
}
|
|
}
|
|
}
|