fix(transfer): finalize delivery completion

This commit is contained in:
2026-07-22 21:34:33 +02:00
parent ad9ffd63f5
commit f0b06ad1cf
20 changed files with 580 additions and 85 deletions

View File

@@ -20,7 +20,7 @@ use crate::{
util::now_ms,
};
const SCHEMA_VERSION: i64 = 5;
const SCHEMA_VERSION: i64 = 6;
#[derive(Debug, Clone)]
pub(crate) struct Repository {
@@ -78,6 +78,23 @@ pub(crate) struct ReceiverRequestInsert<'a> {
pub(crate) app_version: &'a str,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct PendingDeliveryReceipt {
pub(crate) local_transfer_id: u64,
pub(crate) sender_blob_ticket: String,
pub(crate) request_id: String,
pub(crate) sender_transfer_id: u64,
pub(crate) token: String,
}
pub(crate) struct PendingDeliveryReceiptInsert<'a> {
pub(crate) local_transfer_id: u64,
pub(crate) sender_blob_ticket: &'a str,
pub(crate) request_id: &'a str,
pub(crate) sender_transfer_id: u64,
pub(crate) token: &'a str,
}
impl Repository {
pub(crate) async fn open(app_data_dir: &Path) -> Result<Self> {
let db_path = app_data_dir.join("vnidrop.sqlite3");
@@ -268,6 +285,21 @@ impl Repository {
.execute(&self.pool)
.await?;
sqlx::query(
r#"
CREATE TABLE IF NOT EXISTS pending_delivery_receipts (
request_id TEXT PRIMARY KEY,
local_transfer_id INTEGER NOT NULL,
sender_blob_ticket TEXT NOT NULL,
sender_transfer_id INTEGER NOT NULL,
token TEXT NOT NULL,
created_at INTEGER NOT NULL
);
"#,
)
.execute(&self.pool)
.await?;
sqlx::query(&format!("PRAGMA user_version = {SCHEMA_VERSION}"))
.execute(&self.pool)
.await?;
@@ -506,6 +538,82 @@ impl Repository {
Ok(())
}
pub(crate) async fn complete_receive_with_pending_receipt(
&self,
receipt: PendingDeliveryReceiptInsert<'_>,
) -> Result<()> {
self.maybe_fail_write()?;
let mut transaction = self.pool.begin().await?;
let updated = sqlx::query(
r#"
UPDATE transfers
SET status = 'done', updated_at = ?1
WHERE transfer_id = ?2 AND direction = 'receive' AND status = 'receiving'
"#,
)
.bind(now_ms())
.bind(to_db_id(receipt.local_transfer_id)?)
.execute(&mut *transaction)
.await?;
require_one_changed(updated.rows_affected(), "complete receive")?;
sqlx::query(
r#"
INSERT INTO pending_delivery_receipts (
request_id, local_transfer_id, sender_blob_ticket,
sender_transfer_id, token, created_at
) VALUES (?1, ?2, ?3, ?4, ?5, ?6)
ON CONFLICT(request_id) DO UPDATE SET
local_transfer_id = excluded.local_transfer_id,
sender_blob_ticket = excluded.sender_blob_ticket,
sender_transfer_id = excluded.sender_transfer_id,
token = excluded.token
"#,
)
.bind(receipt.request_id)
.bind(to_db_id(receipt.local_transfer_id)?)
.bind(receipt.sender_blob_ticket)
.bind(to_db_id(receipt.sender_transfer_id)?)
.bind(receipt.token)
.bind(now_ms())
.execute(&mut *transaction)
.await?;
transaction.commit().await?;
Ok(())
}
pub(crate) async fn list_pending_delivery_receipts(
&self,
) -> Result<Vec<PendingDeliveryReceipt>> {
let rows = sqlx::query(
r#"
SELECT local_transfer_id, sender_blob_ticket, request_id,
sender_transfer_id, token
FROM pending_delivery_receipts
ORDER BY created_at ASC
"#,
)
.fetch_all(&self.pool)
.await?;
Ok(rows
.into_iter()
.map(|row| PendingDeliveryReceipt {
local_transfer_id: row.get::<i64, _>("local_transfer_id") as u64,
sender_blob_ticket: row.get("sender_blob_ticket"),
request_id: row.get("request_id"),
sender_transfer_id: row.get::<i64, _>("sender_transfer_id") as u64,
token: row.get("token"),
})
.collect())
}
pub(crate) async fn delete_pending_delivery_receipt(&self, request_id: &str) -> Result<()> {
sqlx::query("DELETE FROM pending_delivery_receipts WHERE request_id = ?1")
.bind(request_id)
.execute(&self.pool)
.await?;
Ok(())
}
pub(crate) async fn update_active_share_access_mode(
&self,
transfer_id: u64,