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]
|
#[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();
|
||||||
}
|
}
|
||||||
@@ -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} />
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -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() {
|
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>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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() {
|
||||||
|
|||||||
Reference in New Issue
Block a user