feat: 使用持久选择解决 Sync 冲突并支持重启恢复
This commit is contained in:
@@ -104,7 +104,6 @@ impl Workspace {
|
||||
{
|
||||
return Err(HostError::new("SYNC_HASH_INVALID"));
|
||||
}
|
||||
self.resolve(&format!("attachments/{digest}"))?; // Enforce the platform's general path rules.
|
||||
let root = self.root.join(".ainote/sync-spool");
|
||||
if root.exists() {
|
||||
let meta = fs::symlink_metadata(&root)?;
|
||||
@@ -163,17 +162,29 @@ impl Workspace {
|
||||
}
|
||||
pub fn sync_next(&self, binding: &str) -> Result<Option<Job>> {
|
||||
self.check_binding(binding)?;
|
||||
Ok(self.db.query_row("SELECT binding,operation_id,file_id,path,hash,size,operation,state,base_revision,upload_id FROM sync_jobs WHERE binding=?1 AND state NOT IN ('acked','archived') ORDER BY rowid LIMIT 1", [binding], |r| {
|
||||
Ok(self.db.query_row("SELECT binding,operation_id,file_id,path,hash,size,operation,state,base_revision,upload_id FROM sync_jobs WHERE binding=?1 AND state NOT IN ('acked','archived','conflict') AND NOT EXISTS (SELECT 1 FROM sync_conflicts c WHERE c.binding=sync_jobs.binding AND c.file_id=sync_jobs.file_id AND c.state='open') ORDER BY rowid LIMIT 1", [binding], |r| {
|
||||
Ok(Job { binding:r.get(0)?,operation_id:r.get(1)?,file_id:r.get(2)?,path:r.get(3)?,hash:r.get(4)?,size:r.get(5)?,operation:r.get(6)?,state:r.get(7)?,base_revision:r.get(8)?,upload_id:r.get(9)? })
|
||||
}).optional()?)
|
||||
}
|
||||
pub fn sync_upload(&self, job: &Job, upload: Option<&str>) -> Result<()> {
|
||||
fn check_job(&self, job: &Job) -> Result<()> {
|
||||
self.check_binding(&job.binding)?;
|
||||
let state: String = self.db.query_row(
|
||||
"SELECT state FROM sync_jobs WHERE binding=?1 AND operation_id=?2",
|
||||
params![job.binding, job.operation_id],
|
||||
|r| r.get(0),
|
||||
)?;
|
||||
if matches!(state.as_str(), "archived" | "conflict") {
|
||||
return Err(HostError::new("SYNC_OPERATION_SUPERSEDED"));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
pub fn sync_upload(&self, job: &Job, upload: Option<&str>) -> Result<()> {
|
||||
self.check_job(job)?;
|
||||
self.db.execute("UPDATE sync_jobs SET state='uploading',upload_id=?3 WHERE binding=?1 AND operation_id=?2 AND base_revision IS NULL", params![job.binding,job.operation_id,upload])?;
|
||||
Ok(())
|
||||
}
|
||||
pub fn sync_commit_payload(&self, job: &Job) -> Result<serde_json::Value> {
|
||||
self.check_binding(&job.binding)?;
|
||||
self.check_job(job)?;
|
||||
// The base is frozen exactly once. A response loss reuses the byte-equivalent payload.
|
||||
self.db.execute("UPDATE sync_jobs SET state='committing',base_revision=COALESCE((SELECT revision FROM sync_heads WHERE binding=?1 AND file_id=?3),0) WHERE binding=?1 AND operation_id=?2 AND base_revision IS NULL",
|
||||
params![job.binding,job.operation_id,job.file_id])?;
|
||||
|
||||
Reference in New Issue
Block a user