feat(desktop): add detailed error messages and SSL bypass checkbox
This commit is contained in:
@@ -21,6 +21,7 @@ struct App {
|
|||||||
share_url: String,
|
share_url: String,
|
||||||
upload_rx: Option<mpsc::Receiver<UploadResult>>,
|
upload_rx: Option<mpsc::Receiver<UploadResult>>,
|
||||||
uploading: bool,
|
uploading: bool,
|
||||||
|
skip_ssl: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
@@ -31,16 +32,19 @@ impl App {
|
|||||||
share_url: String::new(),
|
share_url: String::new(),
|
||||||
upload_rx: None,
|
upload_rx: None,
|
||||||
uploading: false,
|
uploading: false,
|
||||||
|
skip_ssl: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_upload(&mut self, filepath: std::path::PathBuf, api_url: String) {
|
fn start_upload(&mut self, filepath: std::path::PathBuf) {
|
||||||
let (tx, rx) = mpsc::channel();
|
let (tx, rx) = mpsc::channel();
|
||||||
self.upload_rx = Some(rx);
|
self.upload_rx = Some(rx);
|
||||||
self.uploading = true;
|
self.uploading = true;
|
||||||
|
let api_url = self.api_url.clone();
|
||||||
|
let skip_ssl = self.skip_ssl;
|
||||||
|
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
let result = do_upload(&api_url, &filepath);
|
let result = do_upload(&api_url, &filepath, skip_ssl);
|
||||||
let _ = tx.send(result);
|
let _ = tx.send(result);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -65,7 +69,7 @@ impl App {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_upload(api_url: &str, filepath: &std::path::Path) -> UploadResult {
|
fn do_upload(api_url: &str, filepath: &std::path::Path, skip_ssl: bool) -> UploadResult {
|
||||||
let filename = filepath
|
let filename = filepath
|
||||||
.file_name()
|
.file_name()
|
||||||
.map(|n| n.to_string_lossy().to_string())
|
.map(|n| n.to_string_lossy().to_string())
|
||||||
@@ -81,18 +85,33 @@ fn do_upload(api_url: &str, filepath: &std::path::Path) -> UploadResult {
|
|||||||
.part("file", part)
|
.part("file", part)
|
||||||
.text("expiry", "24h");
|
.text("expiry", "24h");
|
||||||
|
|
||||||
let client = match reqwest::blocking::Client::builder()
|
let mut builder = reqwest::blocking::Client::builder()
|
||||||
.user_agent("TempFileTransfer-Desktop/0.1")
|
.user_agent("TempFileTransfer-Desktop/0.2")
|
||||||
.timeout(std::time::Duration::from_secs(300))
|
.timeout(std::time::Duration::from_secs(300));
|
||||||
.build()
|
|
||||||
{
|
if skip_ssl {
|
||||||
|
builder = builder.danger_accept_invalid_certs(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
let client = match builder.build() {
|
||||||
Ok(c) => c,
|
Ok(c) => c,
|
||||||
Err(e) => return UploadResult::Err(format!("创建客户端失败: {}", e)),
|
Err(e) => return UploadResult::Err(format!("创建客户端失败: {}", e)),
|
||||||
};
|
};
|
||||||
|
|
||||||
let resp = match client.post(api_url).multipart(form).send() {
|
let resp = match client.post(api_url).multipart(form).send() {
|
||||||
Ok(r) => r,
|
Ok(r) => r,
|
||||||
Err(e) => return UploadResult::Err(format!("网络请求失败: {}", e)),
|
Err(e) => {
|
||||||
|
let detail = if e.is_connect() {
|
||||||
|
format!("连接失败(无法连接到服务器): {}", e)
|
||||||
|
} else if e.is_timeout() {
|
||||||
|
format!("连接超时: {}", e)
|
||||||
|
} else if e.is_body() {
|
||||||
|
format!("SSL/数据传输出错(请尝试勾选「跳过SSL验证」): {}", e)
|
||||||
|
} else {
|
||||||
|
format!("{}", e)
|
||||||
|
};
|
||||||
|
return UploadResult::Err(detail);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let status = resp.status();
|
let status = resp.status();
|
||||||
@@ -138,6 +157,11 @@ impl eframe::App for App {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ui.add_space(4.0);
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
ui.checkbox(&mut self.skip_ssl, "跳过 SSL 证书验证(仅当连接失败时尝试)");
|
||||||
|
});
|
||||||
|
|
||||||
ui.add_space(8.0);
|
ui.add_space(8.0);
|
||||||
|
|
||||||
let drop_frame = egui::Frame::dark_canvas(ui.style())
|
let drop_frame = egui::Frame::dark_canvas(ui.style())
|
||||||
@@ -180,7 +204,7 @@ impl eframe::App for App {
|
|||||||
if !self.uploading {
|
if !self.uploading {
|
||||||
for f in files {
|
for f in files {
|
||||||
if let Some(ref path) = f.path {
|
if let Some(ref path) = f.path {
|
||||||
self.start_upload(path.to_owned(), self.api_url.clone());
|
self.start_upload(path.to_owned());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -191,10 +215,14 @@ impl eframe::App for App {
|
|||||||
|
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.label("状态:");
|
ui.label("状态:");
|
||||||
ui.label(
|
let color = if self.status.starts_with("上传失败") {
|
||||||
egui::RichText::new(&self.status)
|
egui::Color32::from_rgb(220, 80, 80)
|
||||||
.color(egui::Color32::from_rgb(100, 180, 100)),
|
} else if self.status.starts_with("上传成功") {
|
||||||
);
|
egui::Color32::from_rgb(80, 200, 80)
|
||||||
|
} else {
|
||||||
|
egui::Color32::from_rgb(100, 180, 100)
|
||||||
|
};
|
||||||
|
ui.label(egui::RichText::new(&self.status).color(color));
|
||||||
});
|
});
|
||||||
|
|
||||||
ui.add_space(8.0);
|
ui.add_space(8.0);
|
||||||
@@ -253,7 +281,7 @@ fn load_chinese_font(ctx: &egui::Context) {
|
|||||||
fn main() {
|
fn main() {
|
||||||
let options = eframe::NativeOptions {
|
let options = eframe::NativeOptions {
|
||||||
viewport: egui::ViewportBuilder::default()
|
viewport: egui::ViewportBuilder::default()
|
||||||
.with_inner_size([560.0, 480.0])
|
.with_inner_size([560.0, 500.0])
|
||||||
.with_resizable(false)
|
.with_resizable(false)
|
||||||
.with_title("临时文件传输"),
|
.with_title("临时文件传输"),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
|||||||
Reference in New Issue
Block a user