fix(desktop): retry file URL without stale entity id (#159)

The entity id cached in local inventory can go stale when the remote
file is re-uploaded or migrated, which made hydration/opening fail
permanently with "entity not exist" (40077). Both the on-demand
hydration path and the download task now retry letting the server pick
the primary entity.

Authored By: TDvorak <info@tdvorak.dev>

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
pull/3587/head
root 2 weeks ago
parent ae388fbc0c
commit b17405d42e

@ -46,6 +46,7 @@ pub enum ErrorCode {
IncorrectPassword = 40069, IncorrectPassword = 40069,
LockConflict = 40073, LockConflict = 40073,
StaleVersion = 40076, StaleVersion = 40076,
EntityNotExist = 40077,
BatchOperationNotFullyCompleted = 40081, BatchOperationNotFullyCompleted = 40081,
DomainNotLicensed = 40087, DomainNotLicensed = 40087,
AnonymousAccessDenied = 40088, AnonymousAccessDenied = 40088,
@ -65,6 +66,7 @@ impl ErrorCode {
40069 => Some(Self::IncorrectPassword), 40069 => Some(Self::IncorrectPassword),
40073 => Some(Self::LockConflict), 40073 => Some(Self::LockConflict),
40076 => Some(Self::StaleVersion), 40076 => Some(Self::StaleVersion),
40077 => Some(Self::EntityNotExist),
40081 => Some(Self::BatchOperationNotFullyCompleted), 40081 => Some(Self::BatchOperationNotFullyCompleted),
40087 => Some(Self::DomainNotLicensed), 40087 => Some(Self::DomainNotLicensed),
40088 => Some(Self::AnonymousAccessDenied), 40088 => Some(Self::AnonymousAccessDenied),
@ -198,6 +200,11 @@ impl ApiError {
matches!(self, ApiError::AccessTokenExpired) matches!(self, ApiError::AccessTokenExpired)
} }
/// Check if this error reports a missing entity (code 40077)
pub fn is_entity_not_exist(&self) -> bool {
matches!(self, ApiError::ApiError { code, .. } if *code == 40077)
}
/// Check if this error requires login /// Check if this error requires login
pub fn requires_login(&self) -> bool { pub fn requires_login(&self) -> bool {
matches!( matches!(

@ -239,11 +239,21 @@ impl Mount {
request.entity = Some(meta.etag.clone()); request.entity = Some(meta.etag.clone());
} }
} }
let entity_url_res = self let entity_url_res = match self.cr_client.get_file_url(&request).await {
.cr_client Err(e) if e.is_entity_not_exist() && request.entity.is_some() => {
.get_file_url(&request) // The entity id cached in local inventory can go stale when the
.await // remote file is re-uploaded or migrated; retry letting the
.context("failed to get file url")?; // server pick the primary entity.
tracing::info!(target: "drive::commands", path = %path.display(), "Preferred entity no longer exists, retrying without it");
let mut retry = request.clone();
retry.entity = None;
self.cr_client
.get_file_url(&retry)
.await
.context("failed to get file url")?
}
res => res.context("failed to get file url")?,
};
// Get the download URL from the response // Get the download URL from the response
let download_url = entity_url_res let download_url = entity_url_res

@ -338,11 +338,19 @@ impl<'a> DownloadTask<'a> {
.clone(); .clone();
} }
let entity_url_res = self let entity_url_res = match self.cr_client.get_file_url(&request).await {
.cr_client Err(e) if e.is_entity_not_exist() && request.entity.is_some() => {
.get_file_url(&request) // Entity id cached from a previous file info response may be
.await // stale; retry letting the server pick the primary entity.
.context("failed to get file url")?; let mut retry = request.clone();
retry.entity = None;
self.cr_client
.get_file_url(&retry)
.await
.context("failed to get file url")?
}
res => res.context("failed to get file url")?,
};
let download_url = entity_url_res let download_url = entity_url_res
.urls .urls

Loading…
Cancel
Save