This commit is contained in:
2025-10-17 11:30:45 +03:00
parent cb51d16e0f
commit 9d9beefe7f
7 changed files with 369 additions and 160 deletions

View File

@@ -1,7 +1,67 @@
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::{fs, io};
use zstd::{Decoder, Encoder};
pub async fn compress_parts(input: Vec<Vec<u8>>, output: fs::File, level: i32) {
pub struct Zdiff {
pub content: HashMap<String, Vec<u8>>,
pub metadata: Metadata,
}
impl Zdiff {
pub async fn from_vec(_data: Vec<Vec<u8>>) -> Result<Self, std::io::Error> {
let mut content = HashMap::new();
for part in _data {
let filename_size = u32::from_be_bytes(part[0..4].try_into().unwrap()) as usize;
let filename = String::from_utf8(part[4..filename_size + 4].to_vec()).unwrap();
let cont = part[filename_size + 8..].to_vec();
content.insert(filename, cont);
}
let meta = content.get("metadata.json").unwrap();
let metadata: Metadata = serde_json::from_slice(meta.as_slice())?;
content.remove("metadata.json");
Ok(Zdiff { content, metadata })
}
pub async fn to_vec(&self) -> Vec<Vec<u8>> {
let mut parts: Vec<Vec<u8>> = Vec::new();
for (filename, content) in &self.content {
let filename_size: [u8; 4] = (filename.len() as u32).to_be_bytes();
let filename_encoded = vec![filename_size.as_slice(), filename.as_bytes()].concat();
let content_size: [u8; 4] = (content.len() as u32).to_be_bytes();
let content_encoded = vec![content_size.as_slice(), content.as_slice()].concat();
parts.push(vec![filename_encoded, content_encoded].concat())
}
let meta = serde_json::to_vec(&self.metadata).unwrap();
let meta_filename = "metadata.json";
let meta_filename_size = (meta_filename.len() as u32).to_be_bytes();
let meta_filename_encoded =
vec![meta_filename_size.as_slice(), meta_filename.as_bytes()].concat();
let meta_size = (meta.len() as u32).to_be_bytes();
let meta_encoded = vec![meta_size.as_slice(), meta.as_slice()].concat();
parts.push(vec![meta_filename_encoded, meta_encoded].concat());
parts
}
}
#[derive(Serialize, Deserialize)]
pub struct Metadata {
pub(crate) diff_files: Vec<String>,
pub hashes: HashMap<String, String>,
pub remove_files: Vec<String>,
}
pub async fn get_hash(data: &Vec<u8>) -> String {
let hash = md5::compute(&data[..]);
format!("{:x}", hash)
}
pub async fn compress_parts(input: Vec<Vec<u8>>, output: &fs::File, level: i32) {
let mut encoder = Encoder::new(output, level).unwrap();
for part in input.iter() {
io::copy(&mut &part[..], &mut encoder).unwrap();