Skip to main content

Module attachments

Module attachments 

Source
Expand description

Attachments table operations.

Attachments are normalized into one row per attachment (see migration 74), keyed to their event (ON DELETE CASCADE) and indexed by content hash. This module is the single source of truth for attachment persistence; the legacy ["attachments", …] tag in events.tags is left in place on pre-migration events as an untouched safety net but is never read.

Structs§

ReusableUpload
A prior upload of this exact plaintext, reusable by reference: the blob is already on a Blossom server and key/nonce decrypt it.

Functions§

backfill_downloaded_by_hash
Mark every OTHER attachment sharing this content hash as downloaded to the same path — the download-sharing dedup, now an indexed WHERE hash = ? instead of a LIKE '%hash%' table scan. Returns the affected event ids so the caller can reconcile in-memory STATE.
clear_attachment_download
Mark an attachment not-downloaded (its file went missing). Clears the path.
downloaded_attachment_paths
A downloaded attachment’s on-disk path, for the integrity sweep. Returns (event_id, hash, path) for every attachment claiming downloaded=1 with a non-empty path — an indexed read, no per-event JSON parse.
downloaded_paths_by_hash
Paths where these bytes already landed: every downloaded=1 row for the hash, wherever the file was saved (collision suffixes included — the name on the message says nothing about the name on disk). Rows are CLAIMS: the caller must hash-verify a path before treating it as the content.
events_with_attachment_hash
The message carrying an attachment with this content hash, newest first.
find_by_webxdc_topic_in
The Mini App message carrying topic in one chat: (event id, attachment). Scoped to the chat because a topic is only a session id there; anyone can paste the same topic onto an app sent from elsewhere.
find_reusable_by_hash
get_attachments_for_event
Attachments for a single event, ordered by att_index.
get_attachments_for_events
Attachments for a set of events, event_id → Vec<Attachment> ordered by att_index. Batched (one IN (…) query) for a message window, mirroring the reactions/edits loaders.
hash_referenced_elsewhere
Whether any OTHER event’s attachment shares this plaintext hash — the local file half of the same refcount: the decrypted file on disk serves every message that names its hash, windowed out of memory or not.
insert_attachment_rows
Upsert a message’s attachment rows onto the given connection or transaction, so save_message can commit them ATOMICALLY with the event row (an event + no attachments would render as a broken file message with no fallback). Upserts on (event_id, att_index). The mutable local state is handled so a re-save never regresses a completed download: downloaded is MONOTONIC (MAX(existing, incoming)), and hash/path only take the incoming values when the incoming carries a completed download (downloaded=1) — the nonce→content-hash rewrite the download path performs. So a relay re-delivery (downloaded=0) preserves the downloaded file, its content-hash key, and its path; a completed download persists all three in one pass. Explicit un-download goes through clear_attachment_download, never here.
rewrite_downloaded_paths
Repoint downloaded-file paths from old download directories to a new one (Android download-dir migration). For each downloaded attachment whose path starts with an old prefix: move it to new_dir/<filename> if that exists, else mark it not-downloaded. Returns the affected event ids.
set_attachment_downloaded
Flip one attachment’s downloaded state — a single-row UPDATE keyed by (event_id, content hash), replacing the old read-modify-write of the whole tags blob.
urls_unreferenced_elsewhere
Of urls, the ones NO other event’s attachment still points at — the only ones a delete may scrub from Blossom. One blob can back many messages (smart-forward), and the shared copy must outlive every send but the last. DB-backed on purpose: the in-memory STATE windows to recent messages, so a reference in an older message is invisible there.
verify_local_copy
The smart-forward ledger read: has this exact plaintext (by SHA-256) ever crossed this account with a decryptable blob behind it?
verify_message_attachments
Run verify_local_copy over a message’s undownloaded attachments, converting verified claims in place. No-op for messages whose files are unknown (indexed probe misses) or already resident.