fix(cloud-files): Timeout-Ursachen im FETCH_DATA-Callback beheben
- HTTP-Client bekommt 60s-Timeout (statt unendlich) - Bei Send-/Netzwerkfehler wird CfExecute immer mit Failure-Status abgeschlossen, damit Explorer nicht ins OS-Timeout laeuft - Wenn Server kein Range unterstuetzt (200 statt 206), wird aus dem Full-Body der angeforderte Bereich herausgeschnitten und die tatsaechliche Laenge an CfExecute uebergeben - Fehler werden in <mount>\.minicloud-cloudfiles.log geschrieben, damit man das Problem bei Timeout ueberhaupt sehen kann Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
204dbb6ab5
commit
6274567219
|
|
@ -171,19 +171,40 @@ unsafe extern "system" fn on_fetch_data(
|
||||||
// HTTPS-Download im separaten Thread (Callback darf nicht blockieren).
|
// HTTPS-Download im separaten Thread (Callback darf nicht blockieren).
|
||||||
let ctx = ctx_snapshot();
|
let ctx = ctx_snapshot();
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
let _ = transfer_range(connection_key, transfer_key, file_id, offset, length, ctx);
|
if let Err(e) = transfer_range(connection_key, transfer_key, file_id, offset, length, &ctx)
|
||||||
|
{
|
||||||
|
log_err(&ctx.mount_point, &format!(
|
||||||
|
"fetch file_id={file_id} offset={offset} len={length} FAILED: {e}"
|
||||||
|
));
|
||||||
|
// Garantiert Fehler-Completion, damit Windows nicht in Timeout laeuft.
|
||||||
|
let _ = complete_transfer(connection_key, transfer_key, None, offset, length);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn log_err(mount: &Path, msg: &str) {
|
||||||
|
use std::io::Write;
|
||||||
|
let log = mount.join(".minicloud-cloudfiles.log");
|
||||||
|
if let Ok(mut f) = std::fs::OpenOptions::new().create(true).append(true).open(&log) {
|
||||||
|
let _ = writeln!(f, "[{}] {}", chrono::Utc::now().to_rfc3339(), msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn transfer_range(
|
fn transfer_range(
|
||||||
connection_key: CF::CF_CONNECTION_KEY,
|
connection_key: CF::CF_CONNECTION_KEY,
|
||||||
transfer_key: i64,
|
transfer_key: i64,
|
||||||
file_id: i64,
|
file_id: i64,
|
||||||
offset: i64,
|
offset: i64,
|
||||||
length: u64,
|
length: u64,
|
||||||
ctx: CloudContext,
|
ctx: &CloudContext,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
let client = reqwest::blocking::Client::new();
|
if ctx.server_url.is_empty() || ctx.access_token.is_empty() {
|
||||||
|
return Err("CloudContext nicht gesetzt (Server/Token leer)".into());
|
||||||
|
}
|
||||||
|
let client = reqwest::blocking::Client::builder()
|
||||||
|
.timeout(std::time::Duration::from_secs(60))
|
||||||
|
.build()
|
||||||
|
.map_err(|e| format!("client: {e}"))?;
|
||||||
let url = format!(
|
let url = format!(
|
||||||
"{}/api/files/{}/download",
|
"{}/api/files/{}/download",
|
||||||
ctx.server_url.trim_end_matches('/'),
|
ctx.server_url.trim_end_matches('/'),
|
||||||
|
|
@ -195,22 +216,26 @@ fn transfer_range(
|
||||||
.bearer_auth(&ctx.access_token)
|
.bearer_auth(&ctx.access_token)
|
||||||
.header("Range", &range)
|
.header("Range", &range)
|
||||||
.send()
|
.send()
|
||||||
.map_err(|e| format!("download: {e}"))?;
|
.map_err(|e| format!("send: {e}"))?;
|
||||||
let status = resp.status();
|
let status = resp.status();
|
||||||
if !status.is_success() && status.as_u16() != 206 {
|
if !status.is_success() && status.as_u16() != 206 {
|
||||||
let _ = complete_transfer(connection_key, transfer_key, None, offset, length);
|
|
||||||
return Err(format!("HTTP {}", status));
|
return Err(format!("HTTP {}", status));
|
||||||
}
|
}
|
||||||
let bytes = resp
|
let bytes = resp.bytes().map_err(|e: reqwest::Error| e.to_string())?;
|
||||||
.bytes()
|
// Wenn Server kein Range unterstuetzt und volle Datei liefert,
|
||||||
.map_err(|e: reqwest::Error| e.to_string())?;
|
// aus dem Body den angeforderten Bereich ausschneiden.
|
||||||
complete_transfer(
|
let slice: &[u8] = if status.as_u16() == 206 {
|
||||||
connection_key,
|
&bytes[..]
|
||||||
transfer_key,
|
} else {
|
||||||
Some(&bytes),
|
let start = offset as usize;
|
||||||
offset,
|
let end = (start + length as usize).min(bytes.len());
|
||||||
length,
|
if start >= bytes.len() {
|
||||||
)
|
&[]
|
||||||
|
} else {
|
||||||
|
&bytes[start..end]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
complete_transfer(connection_key, transfer_key, Some(slice), offset, slice.len() as u64)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn complete_transfer(
|
fn complete_transfer(
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue