feat: Deduplicate blob files in chat.rs, config.rs, and integration.rs

These were the last places in the `deltachat` crate where files were
stored without deduplication. The CFFI python bindings are the last
thing that's still missing.
This commit is contained in:
Hocuri
2025-01-24 20:08:20 +01:00
parent 1fd6d80e6d
commit e6ea09641a
5 changed files with 19 additions and 8 deletions

View File

@@ -8,7 +8,7 @@ import { EventId2EventName, C } from '../dist/constants.js'
import { join } from 'path'
import { statSync } from 'fs'
import { Context } from '../dist/context.js'
import {fileURLToPath} from 'url';
import { fileURLToPath } from 'url';
const __dirname = fileURLToPath(new URL('.', import.meta.url));
@@ -444,7 +444,7 @@ describe('Offline Tests with unconfigured account', function () {
context.setChatProfileImage(chatId, imagePath)
const blobPath = context.getChat(chatId).getProfileImage()
expect(blobPath.startsWith(blobs)).to.be.true
expect(blobPath.includes('image')).to.be.true
expect(blobPath.includes('image')).to.be.false
expect(blobPath.endsWith('.jpeg')).to.be.true
context.setChatProfileImage(chatId, null)

View File

@@ -8,7 +8,7 @@ use std::iter::FusedIterator;
use std::mem;
use std::path::{Path, PathBuf};
use anyhow::{format_err, Context as _, Result};
use anyhow::{ensure, format_err, Context as _, Result};
use base64::Engine as _;
use futures::StreamExt;
use image::codecs::jpeg::JpegEncoder;
@@ -139,7 +139,7 @@ impl<'a> BlobObject<'a> {
let src_in_blobdir: &Path;
let blobdir = context.get_blobdir();
if src.starts_with(blobdir) || src.starts_with("$BLOBDIR/") {
if src.starts_with(blobdir) {
src_in_blobdir = src;
} else {
info!(
@@ -678,6 +678,10 @@ impl<'a> BlobObject<'a> {
}
fn file_hash(src: &Path) -> Result<blake3::Hash> {
ensure!(
!src.starts_with("$BLOBDIR/"),
"Use `get_abs_path()` to get the absolute path of the blobfile"
);
let mut hasher = blake3::Hasher::new();
let mut src_file = std::fs::File::open(src)
.with_context(|| format!("Failed to open file {}", src.display()))?;
@@ -1221,7 +1225,7 @@ mod tests {
let avatar_src = t.dir.path().join("avatar.png");
let avatar_bytes = include_bytes!("../test-data/image/avatar64x64.png");
fs::write(&avatar_src, avatar_bytes).await.unwrap();
let avatar_blob = t.get_blobdir().join("avatar.png");
let avatar_blob = t.get_blobdir().join("e9b6c7a78aa2e4f415644f55a553e73.png");
assert!(!avatar_blob.exists());
t.set_config(Config::Selfavatar, Some(avatar_src.to_str().unwrap()))
.await

View File

@@ -4170,7 +4170,11 @@ pub async fn set_chat_profile_image(
msg.param.remove(Param::Arg);
msg.text = stock_str::msg_grp_img_deleted(context, ContactId::SELF).await;
} else {
let mut image_blob = BlobObject::new_from_path(context, Path::new(new_image)).await?;
let mut image_blob = BlobObject::create_and_deduplicate(
context,
Path::new(new_image),
Path::new(new_image),
)?;
image_blob.recode_to_avatar_size(context).await?;
chat.param.set(Param::ProfileImage, image_blob.as_name());
msg.param.set(Param::Arg, image_blob.as_name());

View File

@@ -764,7 +764,8 @@ impl Context {
.await?;
match value {
Some(path) => {
let mut blob = BlobObject::new_from_path(self, path.as_ref()).await?;
let path = get_abs_path(self, Path::new(path));
let mut blob = BlobObject::create_and_deduplicate(self, &path, &path)?;
blob.recode_to_avatar_size(self).await?;
self.sql
.set_raw_config(key.as_ref(), Some(blob.as_name()))

View File

@@ -1,3 +1,5 @@
use std::path::Path;
use crate::chat::{send_msg, ChatId};
use crate::config::Config;
use crate::contact::ContactId;
@@ -13,7 +15,7 @@ impl Context {
pub async fn set_webxdc_integration(&self, file: &str) -> Result<()> {
let chat_id = ChatId::create_for_contact(self, ContactId::SELF).await?;
let mut msg = Message::new(Viewtype::Webxdc);
msg.set_file(file, None);
msg.set_file_and_deduplicate(self, Path::new(&file), None, None)?;
msg.hidden = true;
msg.param.set_int(Param::WebxdcIntegration, 1);
msg.param.set_int(Param::GuaranteeE2ee, 1); // needed to pass `internet_access` requirements