async
This commit is contained in:
+17
-32
@@ -1,13 +1,11 @@
|
|||||||
use std::cell::RefCell;
|
|
||||||
use std::{fs, io, time};
|
use std::{fs, io, time};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
use std::sync::RwLock;
|
||||||
use clipboard_rs::Clipboard;
|
use clipboard_rs::Clipboard;
|
||||||
use clipboard_rs::common::RustImage;
|
use clipboard_rs::common::RustImage;
|
||||||
use tempfile::TempDir;
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use tinyrand::{Rand, Seeded};
|
use tinyrand::{Rand, Seeded};
|
||||||
use tokio::task::JoinHandle;
|
|
||||||
use crate::fleen_app::FleenError::{RootDirNonexistence, RootDirPopulated, TargetDir};
|
use crate::fleen_app::FleenError::{RootDirNonexistence, RootDirPopulated, TargetDir};
|
||||||
use crate::fleen_app::TreeEntry::{CloseDir, Dir};
|
use crate::fleen_app::TreeEntry::{CloseDir, Dir};
|
||||||
use crate::renderer;
|
use crate::renderer;
|
||||||
@@ -55,13 +53,13 @@ pub enum FileType {
|
|||||||
|
|
||||||
pub struct FleenApp {
|
pub struct FleenApp {
|
||||||
root: PathBuf,
|
root: PathBuf,
|
||||||
files_cache: RefCell<Option<Vec<TreeEntry>>>
|
files_cache: RwLock<Option<Vec<TreeEntry>>>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FleenApp {
|
impl FleenApp {
|
||||||
pub fn open(root: PathBuf) -> Result<Self, FleenError> {
|
pub fn open(root: PathBuf) -> Result<Self, FleenError> {
|
||||||
match root.try_exists() {
|
match root.try_exists() {
|
||||||
Ok(true) => Ok(Self { root, files_cache: RefCell::new(None) }),
|
Ok(true) => Ok(Self { root, files_cache: RwLock::new(None) }),
|
||||||
_ => Err(RootDirNonexistence(root))
|
_ => Err(RootDirNonexistence(root))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -73,7 +71,7 @@ impl FleenApp {
|
|||||||
Err(RootDirPopulated(root))
|
Err(RootDirPopulated(root))
|
||||||
} else {
|
} else {
|
||||||
Self::initialize_site(root.clone()).map_err(|e| FleenError::FileIo(String::from("creating site"), e.to_string()))?;
|
Self::initialize_site(root.clone()).map_err(|e| FleenError::FileIo(String::from("creating site"), e.to_string()))?;
|
||||||
Ok(Self { root, files_cache: RefCell::new(None) })
|
Ok(Self { root, files_cache: RwLock::new(None) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
@@ -96,7 +94,7 @@ impl FleenApp {
|
|||||||
|
|
||||||
// TODO: This is panicky as hell, make it return a Result
|
// TODO: This is panicky as hell, make it return a Result
|
||||||
fn refresh_file_cache(&self, force: bool) {
|
fn refresh_file_cache(&self, force: bool) {
|
||||||
if self.files_cache.borrow().is_none() || force {
|
if self.files_cache.read().unwrap().is_none() || force {
|
||||||
let mut entries = vec![];
|
let mut entries = vec![];
|
||||||
|
|
||||||
fn visit_dir(dir: &Path, entries: &mut Vec<TreeEntry>) {
|
fn visit_dir(dir: &Path, entries: &mut Vec<TreeEntry>) {
|
||||||
@@ -117,13 +115,14 @@ impl FleenApp {
|
|||||||
visit_dir(&self.root, &mut entries);
|
visit_dir(&self.root, &mut entries);
|
||||||
entries.push(CloseDir);
|
entries.push(CloseDir);
|
||||||
|
|
||||||
self.files_cache.replace(Some(entries));
|
self.files_cache.write().unwrap().replace(entries);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn file_tree_entries(&self) -> impl IntoIterator<Item=TreeEntry> {
|
pub fn file_tree_entries(&self) -> impl IntoIterator<Item=TreeEntry> {
|
||||||
self.refresh_file_cache(false);
|
self.refresh_file_cache(false);
|
||||||
self.files_cache.borrow().clone().expect("Can't happen because we just refreshed the cache")
|
// We need to clone these because the rwlock owns them
|
||||||
|
self.files_cache.read().unwrap().clone().expect("Can't happen because we just refreshed the cache")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_filename(&self, filename: &str) -> Result<(), FleenError> {
|
pub fn open_filename(&self, filename: &str) -> Result<(), FleenError> {
|
||||||
@@ -289,7 +288,7 @@ impl FleenApp {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_and_deploy(&self) -> Result<JoinHandle<Result<String, FleenError>>, FleenError> {
|
pub async fn build_and_deploy(&self) -> Result<String, FleenError> {
|
||||||
let output_dir = tempfile::tempdir().map_err(|_| TargetDir)?;
|
let output_dir = tempfile::tempdir().map_err(|_| TargetDir)?;
|
||||||
self.build_site(&output_dir.path())?; // Attempt to build the site somewhere
|
self.build_site(&output_dir.path())?; // Attempt to build the site somewhere
|
||||||
|
|
||||||
@@ -299,30 +298,16 @@ impl FleenApp {
|
|||||||
} else {
|
} else {
|
||||||
let mut command = Command::new(deploy_script_path);
|
let mut command = Command::new(deploy_script_path);
|
||||||
command.current_dir(output_dir.path()); // don't consume dir!
|
command.current_dir(output_dir.path()); // don't consume dir!
|
||||||
Ok(self.build_and_deploy_inner(output_dir, command))
|
let output = command.output().map_err(|e| FleenError::DeployError(e.to_string()))?;
|
||||||
}
|
let status = command.status()?;
|
||||||
}
|
|
||||||
|
|
||||||
fn build_and_deploy_inner(&self, output_dir: TempDir, mut command: Command) -> JoinHandle<Result<String, FleenError>> {
|
let output = String::from_utf8(output.stdout).unwrap_or("Error reading deploy script output".to_string());
|
||||||
tokio::spawn(async move {
|
if status.success() {
|
||||||
let output = command.output();
|
Ok(output)
|
||||||
let status = command.status().unwrap();
|
} else {
|
||||||
output_dir.close().map_err(|e| FleenError::Io(e))?;
|
Err(FleenError::DeployError(output))
|
||||||
|
|
||||||
match output {
|
|
||||||
Ok(output) => {
|
|
||||||
let output = String::from_utf8(output.stdout).unwrap_or("Error reading deploy script output".to_string());
|
|
||||||
if status.success() {
|
|
||||||
Ok(output)
|
|
||||||
} else {
|
|
||||||
Err(FleenError::DeployError(output))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
Err(FleenError::DeployError(e.to_string()))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+26
-16
@@ -4,7 +4,7 @@ mod server;
|
|||||||
mod ui_ext;
|
mod ui_ext;
|
||||||
|
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::Arc;
|
use std::sync::{Arc, Mutex, MutexGuard};
|
||||||
use std::task::Waker;
|
use std::task::Waker;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
use eframe::egui::{Button, Context, Id, RichText};
|
use eframe::egui::{Button, Context, Id, RichText};
|
||||||
@@ -46,7 +46,8 @@ struct FleenUi {
|
|||||||
dialog_mode: Option<DialogMode>,
|
dialog_mode: Option<DialogMode>,
|
||||||
server_handle: Option<JoinHandle<()>>,
|
server_handle: Option<JoinHandle<()>>,
|
||||||
server_port: String,
|
server_port: String,
|
||||||
deploy_handle: Option<JoinHandle<Result<String, FleenError>>>,
|
deploy_response: Arc<Mutex<Option<Result<String, FleenError>>>>,
|
||||||
|
deploying: bool,
|
||||||
image_message: Option<TempMessage>,
|
image_message: Option<TempMessage>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,7 +60,8 @@ impl Default for FleenUi {
|
|||||||
selected_file: None,
|
selected_file: None,
|
||||||
dialog_mode: None,
|
dialog_mode: None,
|
||||||
server_handle: None,
|
server_handle: None,
|
||||||
deploy_handle: None,
|
deploy_response: Mutex::new(None).into(),
|
||||||
|
deploying: false,
|
||||||
image_message: None,
|
image_message: None,
|
||||||
server_port: "3000".to_string(),
|
server_port: "3000".to_string(),
|
||||||
}
|
}
|
||||||
@@ -109,8 +111,13 @@ impl FleenUi {
|
|||||||
});
|
});
|
||||||
ui.column(width, |ui| self.server_controls(ui));
|
ui.column(width, |ui| self.server_controls(ui));
|
||||||
ui.column(width, |ui| {
|
ui.column(width, |ui| {
|
||||||
ui.add_enabled_ui(self.deploy_handle.is_none(), |ui| {
|
ui.add_enabled_ui(!self.deploying, |ui| {
|
||||||
if ui.add_fill_width(Button::green("Build and deploy")).clicked() {
|
let label = if self.deploying {
|
||||||
|
"Deploying..."
|
||||||
|
} else {
|
||||||
|
"Build and Deploy"
|
||||||
|
};
|
||||||
|
if ui.add_fill_width(Button::green(label)).clicked() {
|
||||||
self.build_and_deploy();
|
self.build_and_deploy();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -135,10 +142,15 @@ impl FleenUi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn build_and_deploy(&mut self) {
|
fn build_and_deploy(&mut self) {
|
||||||
match self.app.as_ref().unwrap().build_and_deploy() {
|
self.deploying = true;
|
||||||
Ok(handle) => { self.deploy_handle = Some(handle) },
|
let mutex = self.deploy_response.clone();
|
||||||
Err(err) => { self.error = Some(err) }
|
let app = self.app.as_ref().unwrap().clone();
|
||||||
}
|
tokio::spawn(async move {
|
||||||
|
let result = app.build_and_deploy().await;
|
||||||
|
if let Ok(mut m) = mutex.lock() {
|
||||||
|
*m = Some(result);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tree_view(&mut self, ui: &mut egui::Ui) {
|
fn tree_view(&mut self, ui: &mut egui::Ui) {
|
||||||
@@ -361,15 +373,13 @@ impl FleenUi {
|
|||||||
|
|
||||||
impl eframe::App for FleenUi {
|
impl eframe::App for FleenUi {
|
||||||
fn update(&mut self, ctx: &Context, _frame: &mut Frame) {
|
fn update(&mut self, ctx: &Context, _frame: &mut Frame) {
|
||||||
if let Some(handle) = self.deploy_handle.as_ref() {
|
if self.deploying && let Ok(mut m) = self.deploy_response.lock() {
|
||||||
if handle.is_finished() {
|
if let Some(result) = m.take() {
|
||||||
let handle = self.deploy_handle.take().unwrap();
|
|
||||||
let result = futures::executor::block_on(async move { handle.await });
|
|
||||||
match result {
|
match result {
|
||||||
Err(e) => { self.error = Some(FleenError::DeployError(e.to_string())) }
|
Err(e) => { self.error = Some(e) }
|
||||||
Ok(Err(e)) => { self.error = Some(e) }
|
Ok(s) => { self.message = Some(s) }
|
||||||
Ok(Ok(s)) => { self.message = Some(s) }
|
|
||||||
}
|
}
|
||||||
|
self.deploying = false;
|
||||||
}
|
}
|
||||||
ctx.request_repaint_after(Duration::from_millis(100));
|
ctx.request_repaint_after(Duration::from_millis(100));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user