use std::path::PathBuf;
use chrono::Utc;
use tokio::{fs::File, io::AsyncWriteExt as TokioAsyncWriteExt, sync::mpsc};
use super::PackEncoder;
use crate::{
errors::GitError,
internal::{
metadata::{EntryMeta, MetaAttached},
pack::entry::Entry,
},
};
pub async fn encode_and_output_to_files(
raw_entries_rx: mpsc::Receiver<MetaAttached<Entry, EntryMeta>>,
object_number: usize,
output_dir: PathBuf,
window_size: usize,
) -> Result<(), GitError> {
let (pack_tx, mut pack_rx) = mpsc::channel(1024);
let (idx_tx, mut idx_rx) = mpsc::channel(1024);
let mut pack_encoder = PackEncoder::new_with_idx(object_number, window_size, pack_tx, idx_tx);
let now = Utc::now();
let timestamp = now.format("%Y%m%d%H%M%S%.3f").to_string();
let tmp_path = output_dir.join(format!("{}objects.pack.tmp", timestamp));
let mut pack_file = File::create(&tmp_path).await?;
let pack_writer = tokio::spawn(async move {
while let Some(chunk) = pack_rx.recv().await {
TokioAsyncWriteExt::write_all(&mut pack_file, &chunk).await?;
}
TokioAsyncWriteExt::flush(&mut pack_file).await?;
Ok::<(), GitError>(())
});
pack_encoder.encode(raw_entries_rx).await?;
let pack_write_result = pack_writer
.await
.map_err(|e| GitError::PackEncodeError(format!("pack writer task join error: {e}")))?;
pack_write_result?;
let final_pack_name =
output_dir.join(format!("pack-{}.pack", pack_encoder.final_hash.unwrap()));
let final_idx_name = output_dir.join(format!("pack-{}.idx", pack_encoder.final_hash.unwrap()));
tokio::fs::rename(tmp_path, &final_pack_name).await?;
let mut idx_file = File::create(&final_idx_name).await?;
let idx_writer = tokio::spawn(async move {
while let Some(chunk) = idx_rx.recv().await {
TokioAsyncWriteExt::write_all(&mut idx_file, &chunk).await?;
}
TokioAsyncWriteExt::flush(&mut idx_file).await?;
Ok::<(), GitError>(())
});
pack_encoder.encode_idx_file().await?;
let idx_write_result = idx_writer
.await
.map_err(|e| GitError::PackEncodeError(format!("idx writer task join error: {e}")))?;
idx_write_result?;
Ok(())
}