Saving is multi threaded now

This commit is contained in:
Chris Cochrun 2024-04-17 06:31:23 -05:00
parent 60182e4d82
commit c7761b9787
3 changed files with 85 additions and 52 deletions

View file

@ -115,10 +115,10 @@ Kirigami.ApplicationWindow {
anchors.left: footerFilePathLabel.left anchors.left: footerFilePathLabel.left
anchors.right: footerFilePathLabel.right anchors.right: footerFilePathLabel.right
anchors.rightMargin: footerFilePathLabel.rightMargin anchors.rightMargin: footerFilePathLabel.rightMargin
from: 0 from: 0.0
to: 100 to: 100.0
value: mainPage.progress value: Math.min(ServiceItemModel.saveProgess, 100.0)
visible: mainPage.progress > 0 /* visible: mainPage.progress > 0 */
} }
} }
/* Item { */ /* Item { */
@ -208,7 +208,7 @@ Kirigami.ApplicationWindow {
defaultSuffix: ".pres" defaultSuffix: ".pres"
selectExisting: false selectExisting: false
onAccepted: { onAccepted: {
finalSave(saveFileDialog.fileUrl); ServiceItemModel.save(saveFileDialog.fileUrl);
console.log(saveFileDialog.fileUrl); console.log(saveFileDialog.fileUrl);
} }
onRejected: { onRejected: {
@ -274,29 +274,32 @@ Kirigami.ApplicationWindow {
let file = ""; let file = "";
if (saveFile.length === 0) { if (saveFile.length === 0) {
file = fileHelper.saveFile(); file = fileHelper.saveFile();
finalSave(file); ServiceItemModel.save(file);
} else { } else {
finalSave(saveFile); ServiceItemModel.save(saveFile);
} }
} }
function saveAs() { function saveAs() {
let file = fileHelper.saveFile(); let file = fileHelper.saveFile();
finalSave(file); ServiceItemModel.save(file);
} }
function finalSave(file) { Connections {
const saved = mainPage.serviceItems.save(file); target: ServiceItemModel
if (saved) { function onSavedToFile(saved, file) {
RSettings.setSaveFile(file); if (saved) {
showPassiveNotification("SAVED! " + file); Utils.dbg(file);
mainPage.progress = 0; console.log(file);
} else { showPassiveNotification("Saved to ", + Qt.resolvedUrl(file));
console.log("File: " + file + " wasn't saved"); }
showPassiveNotification("Didn't save file");
} }
} }
/* function finalSave(file) { */
/* const saved = mainPage.serviceItems.save(file); */
/* } */
function load() { function load() {
const file = fileHelper.loadFile("Load Presentation"); const file = fileHelper.loadFile("Load Presentation");
const loaded = mainPage.serviceItems.load(file); const loaded = mainPage.serviceItems.load(file);

View file

@ -184,8 +184,8 @@ Controls.Page {
Connections { Connections {
target: ServiceItemModel target: ServiceItemModel
function saveProgressUpdate(progress) { function onSaveProgressChanged() {
mainPage.progress = progress; Utils.dbg(ServiceItemModel.saveProgress);
} }
} }

View file

@ -48,6 +48,8 @@ mod service_item_model {
#[base = "QAbstractListModel"] #[base = "QAbstractListModel"]
#[qml_element] #[qml_element]
#[qproperty(i32, count)] #[qproperty(i32, count)]
#[qproperty(f32, save_progress)]
#[qproperty(bool, saved)]
type ServiceItemModel = super::ServiceItemModelRust; type ServiceItemModel = super::ServiceItemModelRust;
#[inherit] #[inherit]
@ -100,6 +102,13 @@ mod service_item_model {
progress: i32, progress: i32,
); );
#[qsignal]
fn saved_to_file(
self: Pin<&mut ServiceItemModel>,
saved: bool,
file: &QUrl,
);
#[qinvokable] #[qinvokable]
fn clear(self: Pin<&mut ServiceItemModel>); fn clear(self: Pin<&mut ServiceItemModel>);
@ -283,7 +292,7 @@ mod service_item_model {
use crate::obs::Obs; use crate::obs::Obs;
use crate::service_item_model::service_item_model::QList_QString; use crate::service_item_model::service_item_model::QList_QString;
use cxx_qt::CxxQtType; use cxx_qt::{CxxQtType, Threading};
use cxx_qt_lib::{ use cxx_qt_lib::{
QByteArray, QModelIndex, QString, QStringList, QUrl, QVariant, QByteArray, QModelIndex, QString, QStringList, QUrl, QVariant,
}; };
@ -293,6 +302,7 @@ use std::io::{Read, Write};
use std::iter; use std::iter;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::pin::Pin; use std::pin::Pin;
use std::time::Instant;
use std::{fs, println}; use std::{fs, println};
use tar::{Archive, Builder}; use tar::{Archive, Builder};
use tracing::{debug, error}; use tracing::{debug, error};
@ -359,6 +369,8 @@ pub struct ServiceItemModelRust {
service_items: Vec<ServiceItem>, service_items: Vec<ServiceItem>,
obs: Option<Obs>, obs: Option<Obs>,
count: i32, count: i32,
save_progress: f32,
saved: bool,
} }
impl Default for ServiceItemModelRust { impl Default for ServiceItemModelRust {
@ -378,6 +390,8 @@ impl Default for ServiceItemModelRust {
service_items: Vec::new(), service_items: Vec::new(),
obs, obs,
count: 0, count: 0,
save_progress: 0.0,
saved: false,
} }
} }
} }
@ -875,16 +889,19 @@ impl service_item_model::ServiceItemModel {
pub fn save(mut self: Pin<&mut Self>, file: QUrl) -> bool { pub fn save(mut self: Pin<&mut Self>, file: QUrl) -> bool {
println!("rust-save-file: {file}"); println!("rust-save-file: {file}");
let path = let save_path =
file.to_local_file().unwrap_or_default().to_string(); file.to_local_file().unwrap_or_default().to_string();
println!("path: {:?}", path); println!("path: {:?}", save_path);
let lfr = fs::File::create(&path);
let save_file = fs::File::create(&save_path);
let runtime = tokio::runtime::Runtime::new().unwrap(); let runtime = tokio::runtime::Runtime::new().unwrap();
let mut handles = vec![]; let mut handles = vec![];
if let Ok(lf) = &lfr {
println!("archive: {:?}", lf); if let Ok(save_file) = save_file {
println!("archive: {:?}", save_file);
self.as_mut().save_progress_updated(5); self.as_mut().save_progress_updated(5);
let encoder = Encoder::new(lf, 3).unwrap(); // let save_file = save_file.clone();
let encoder = Encoder::new(save_file, 3).unwrap();
let mut tar = Builder::new(encoder); let mut tar = Builder::new(encoder);
let items = self.rust().service_items.clone(); let items = self.rust().service_items.clone();
let mut temp_dir = dirs::data_dir().unwrap(); let mut temp_dir = dirs::data_dir().unwrap();
@ -905,7 +922,7 @@ impl service_item_model::ServiceItemModel {
temp_service_file.push("serviceitems.json"); temp_service_file.push("serviceitems.json");
self.as_mut().save_progress_updated(10); self.as_mut().save_progress_updated(10);
let mut service_json: Vec<Value> = vec![]; let mut service_json: Vec<Value> = vec![];
let progress_fraction = items.len() as i32 / 80 as i32; let progress_fraction = items.len() as f32 / 100 as f32;
for (id, item) in items.iter().enumerate() { for (id, item) in items.iter().enumerate() {
let text_list = QList_QString::from(&item.text); let text_list = QList_QString::from(&item.text);
let mut text_vec = Vec::<String>::default(); let mut text_vec = Vec::<String>::default();
@ -1004,9 +1021,6 @@ impl service_item_model::ServiceItemModel {
handles.push(handle); handles.push(handle);
service_json.push(item_json); service_json.push(item_json);
self.as_mut().save_progress_updated(
progress_fraction * (id as i32 + 1),
);
} }
for handle in handles { for handle in handles {
@ -1023,6 +1037,8 @@ impl service_item_model::ServiceItemModel {
println!("error-creating-service-file: {:?}", e) println!("error-creating-service-file: {:?}", e)
} }
} }
let now = Instant::now();
let thread = self.qt_thread();
match fs::File::options() match fs::File::options()
.write(true) .write(true)
.read(true) .read(true)
@ -1034,41 +1050,55 @@ impl service_item_model::ServiceItemModel {
&service_json, &service_json,
) { ) {
Ok(e) => { Ok(e) => {
println!("json: file written"); debug!(time = ?now.elapsed(), "file written");
match tar.append_dir_all("./", &temp_dir) std::thread::spawn(move || {
{ debug!(time = ?now.elapsed(), "idk");
Ok(i) => match tar.finish() { let dir = fs::read_dir(&temp_dir).expect("idk");
Ok(i) => { for (index, file) in dir.enumerate() {
debug!( if let Ok(file) = file {
file = ?&lf, let file_name = file.file_name();
"Tar archive written" debug!(?file, ?file_name);
); let mut file = std::fs::File::open(file.path()).expect("missing file");
self.as_mut() tar.append_file(file_name, &mut file).expect("Error in moving file to tar");
.save_progress_updated( thread.queue(move |mut service| {
100, service
); .as_mut()
.set_save_progress(
progress_fraction *
(index as f32 + 1.0) * 100.0
)
}).expect("Problem queuing on cxx thread");
}
}
if let Ok(encoder) = tar.into_inner() {
if let Ok(done) = encoder.finish() {
debug!(time = ?now.elapsed(), ?done, "tar finished");
thread.queue(move |mut service| {
service.as_mut().set_save_progress(100.0);
service.as_mut().saved_to_file(true, &file);
}).expect("Problem queuing on cxx thread");
fs::remove_dir_all(&temp_dir) fs::remove_dir_all(&temp_dir)
.expect( .expect(
"error in removal", "error in removal",
); );
true true
} } else {
Err(error) => {
error!(?error);
fs::remove_dir_all(&temp_dir) fs::remove_dir_all(&temp_dir)
.expect( .expect(
"error in removal", "error in removal",
); );
false false
} }
}, } else {
Err(error) => {
error!(?error);
fs::remove_dir_all(&temp_dir) fs::remove_dir_all(&temp_dir)
.expect("error in removal"); .expect(
"error in removal",
);
false false
} }
} });
true
} }
Err(error) => { Err(error) => {
error!(?error, "json error"); error!(?error, "json error");
@ -1086,7 +1116,7 @@ impl service_item_model::ServiceItemModel {
} }
} }
} else { } else {
println!("rust-save-file-failed: {:?}", lfr); error!(?save_file, "failed to save");
false false
} }
} }