mirror of
https://github.com/Grasscutters/Cultivation.git
synced 2025-12-14 16:14:48 +01:00
emit download errors
This commit is contained in:
@@ -10,15 +10,26 @@ use futures_util::StreamExt;
|
||||
#[tauri::command]
|
||||
pub async fn download_file(window: tauri::Window, url: &str, path: &str) -> Result<(), String> {
|
||||
// Reqwest setup
|
||||
let res = reqwest::get(url)
|
||||
.await
|
||||
.or(Err(format!("Failed to get {}", url)))?;
|
||||
let res = match reqwest::get(url)
|
||||
.await {
|
||||
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
|
||||
.content_length()
|
||||
.unwrap_or(0);
|
||||
|
||||
// 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;
|
||||
|
||||
// File stream
|
||||
@@ -26,12 +37,23 @@ pub async fn download_file(window: tauri::Window, url: &str, path: &str) -> Resu
|
||||
|
||||
// Await chunks
|
||||
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()[..];
|
||||
|
||||
// Write bytes
|
||||
file.write_all(&vect)
|
||||
.or(Err(format!("Error while writing file")))?;
|
||||
match file.write_all(&vect) {
|
||||
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
|
||||
let new = min(downloaded + (chunk.len() as u64), total_size);
|
||||
@@ -64,3 +86,19 @@ pub async fn download_file(window: tauri::Window, url: &str, path: &str) -> Resu
|
||||
// We are done
|
||||
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();
|
||||
}
|
||||
@@ -64,7 +64,7 @@ class App extends React.Component<IProps, IState> {
|
||||
{
|
||||
// Mini downloads section
|
||||
this.state.miniDownloadsOpen ?
|
||||
<MiniDialog closeFn={() => {
|
||||
<MiniDialog title="Downloads" closeFn={() => {
|
||||
this.setState({ miniDownloadsOpen: false })
|
||||
}}>
|
||||
<DownloadList downloadManager={downloadHandler} />
|
||||
|
||||
@@ -5,6 +5,7 @@ import './MiniDialog.css'
|
||||
|
||||
interface IProps {
|
||||
children: React.ReactNode[] | React.ReactNode;
|
||||
title?: string;
|
||||
closeFn: () => void;
|
||||
}
|
||||
|
||||
@@ -17,7 +18,7 @@ export default class MiniDialog extends React.Component<IProps, never> {
|
||||
return (
|
||||
<div className="MiniDialog">
|
||||
<div className="MiniDialogTop" onClick={this.props.closeFn}>
|
||||
<div></div>
|
||||
<span>{this.props?.title}</span>
|
||||
<img src={Close} className="MiniDialogClose" />
|
||||
</div>
|
||||
<div className="MiniDialogInner">
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
.DownloadList {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 10px;
|
||||
}
|
||||
@@ -14,14 +14,17 @@ export default class DownloadList extends React.Component<IProps, never> {
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="DownloadList">
|
||||
{
|
||||
this.props.downloadManager.getDownloads().map((download) => {
|
||||
const list = this.props.downloadManager.getDownloads().map((download) => {
|
||||
return (
|
||||
<DownloadSection key={download.path} downloadName={download.path} downloadManager={this.props.downloadManager} />
|
||||
)
|
||||
})
|
||||
|
||||
|
||||
return (
|
||||
<div className="DownloadList">
|
||||
{
|
||||
list.length > 0 ? list : 'No downloads present'
|
||||
}
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -33,9 +33,8 @@ export default class ProgressBar extends React.Component<IProps, IState> {
|
||||
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%
|
||||
|
||||
clearInterval(intv)
|
||||
}
|
||||
}, 500)
|
||||
|
||||
@@ -8,6 +8,7 @@ export default class DownloadHandler {
|
||||
progress: number,
|
||||
total: number,
|
||||
status: string,
|
||||
error?: string,
|
||||
}[]
|
||||
|
||||
// Pass tauri invoke function
|
||||
@@ -35,6 +36,19 @@ export default class DownloadHandler {
|
||||
const index = this.downloads.findIndex(download => download.path === filename)
|
||||
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() {
|
||||
|
||||
Reference in New Issue
Block a user