emit download errors

This commit is contained in:
SpikeHD
2022-05-11 21:18:07 -07:00
parent 3ee8ee7061
commit 4b95c52b6c
7 changed files with 78 additions and 16 deletions

View File

@@ -10,15 +10,26 @@ use futures_util::StreamExt;
#[tauri::command] #[tauri::command]
pub async fn download_file(window: tauri::Window, url: &str, path: &str) -> Result<(), String> { pub async fn download_file(window: tauri::Window, url: &str, path: &str) -> Result<(), String> {
// Reqwest setup // Reqwest setup
let res = reqwest::get(url) let res = match reqwest::get(url)
.await .await {
.or(Err(format!("Failed to get {}", url)))?; Ok(r) => r,
Err(e) => {
emit_download_err(window, format!("Failed to request {}", url), url);
return Err(format!("Failed to request {}", url));
},
};
let total_size = res let total_size = res
.content_length() .content_length()
.unwrap_or(0); .unwrap_or(0);
// Create file path // Create file path
let mut file = File::create(path).or(Err(format!("Failed to create file '{}'", path)))?; let mut file = match File::create(path) {
Ok(f) => f,
Err(e) => {
emit_download_err(window, format!("Failed to create file '{}'", path), path);
return Err(format!("Failed to create file '{}'", path));
},
};
let mut downloaded: u64 = 0; let mut downloaded: u64 = 0;
// File stream // File stream
@@ -26,12 +37,23 @@ pub async fn download_file(window: tauri::Window, url: &str, path: &str) -> Resu
// Await chunks // Await chunks
while let Some(item) = stream.next().await { while let Some(item) = stream.next().await {
let chunk = item.or(Err(format!("Error while downloading file"))).unwrap(); let chunk = match item {
Ok(itm) => itm,
Err(e) => {
emit_download_err(window, format!("Error while downloading file"), path);
return Err(format!("Error while downloading file: {}", e));
},
};
let vect = &chunk.to_vec()[..]; let vect = &chunk.to_vec()[..];
// Write bytes // Write bytes
file.write_all(&vect) match file.write_all(&vect) {
.or(Err(format!("Error while writing file")))?; Ok(x) => x,
Err(e) => {
emit_download_err(window, format!("Error while writing file"), path);
return Err(format!("Error while writing file: {}", e));
},
}
// New progress // New progress
let new = min(downloaded + (chunk.len() as u64), total_size); let new = min(downloaded + (chunk.len() as u64), total_size);
@@ -63,4 +85,20 @@ pub async fn download_file(window: tauri::Window, url: &str, path: &str) -> Resu
// We are done // We are done
return Ok(()); return Ok(());
}
pub fn emit_download_err(window: tauri::Window, msg: std::string::String, path: &str) {
let mut res_hash = std::collections::HashMap::new();
res_hash.insert(
"error".to_string(),
msg.to_string()
);
res_hash.insert(
"path".to_string(),
path.to_string()
);
window.emit("download_error", &res_hash).unwrap();
} }

View File

@@ -64,7 +64,7 @@ class App extends React.Component<IProps, IState> {
{ {
// Mini downloads section // Mini downloads section
this.state.miniDownloadsOpen ? this.state.miniDownloadsOpen ?
<MiniDialog closeFn={() => { <MiniDialog title="Downloads" closeFn={() => {
this.setState({ miniDownloadsOpen: false }) this.setState({ miniDownloadsOpen: false })
}}> }}>
<DownloadList downloadManager={downloadHandler} /> <DownloadList downloadManager={downloadHandler} />

View File

@@ -5,6 +5,7 @@ import './MiniDialog.css'
interface IProps { interface IProps {
children: React.ReactNode[] | React.ReactNode; children: React.ReactNode[] | React.ReactNode;
title?: string;
closeFn: () => void; closeFn: () => void;
} }
@@ -17,7 +18,7 @@ export default class MiniDialog extends React.Component<IProps, never> {
return ( return (
<div className="MiniDialog"> <div className="MiniDialog">
<div className="MiniDialogTop" onClick={this.props.closeFn}> <div className="MiniDialogTop" onClick={this.props.closeFn}>
<div></div> <span>{this.props?.title}</span>
<img src={Close} className="MiniDialogClose" /> <img src={Close} className="MiniDialogClose" />
</div> </div>
<div className="MiniDialogInner"> <div className="MiniDialogInner">

View File

@@ -0,0 +1,7 @@
.DownloadList {
display: flex;
flex-direction: column;
flex: 1;
overflow-y: auto;
padding: 10px;
}

View File

@@ -14,14 +14,17 @@ export default class DownloadList extends React.Component<IProps, never> {
} }
render() { render() {
const list = this.props.downloadManager.getDownloads().map((download) => {
return (
<DownloadSection key={download.path} downloadName={download.path} downloadManager={this.props.downloadManager} />
)
})
return ( return (
<div className="DownloadList"> <div className="DownloadList">
{ {
this.props.downloadManager.getDownloads().map((download) => { list.length > 0 ? list : 'No downloads present'
return (
<DownloadSection key={download.path} downloadName={download.path} downloadManager={this.props.downloadManager} />
)
})
} }
</div> </div>
) )

View File

@@ -33,9 +33,8 @@ export default class ProgressBar extends React.Component<IProps, IState> {
total: prog?.total || 0, total: prog?.total || 0,
}) })
if (this.state.status === 'finished' /* || this.state.status === 'error' */) { if (this.state.status === 'finished' || this.state.status === 'error') {
// Ensure progress is 100% // Ensure progress is 100%
clearInterval(intv) clearInterval(intv)
} }
}, 500) }, 500)

View File

@@ -8,6 +8,7 @@ export default class DownloadHandler {
progress: number, progress: number,
total: number, total: number,
status: string, status: string,
error?: string,
}[] }[]
// Pass tauri invoke function // Pass tauri invoke function
@@ -35,6 +36,19 @@ export default class DownloadHandler {
const index = this.downloads.findIndex(download => download.path === filename) const index = this.downloads.findIndex(download => download.path === filename)
this.downloads[index].status = 'finished' this.downloads[index].status = 'finished'
}) })
listen('download_error', (...payload) => {
// @ts-expect-error shut up typescript
const errorData: {
path: string,
error: string,
} = payload[0]?.payload
// Set download to error
const index = this.downloads.findIndex(download => download.path === errorData.path)
this.downloads[index].status = 'error'
this.downloads[index].error = errorData.error
})
} }
getDownloads() { getDownloads() {