1use anyhow::Result;
2use std::fs;
3use std::path::{Path, PathBuf};
4
5pub struct PartialTransfer {
6 dir: PathBuf,
7 #[allow(dead_code)]
8 commit_id: String,
9}
10
11impl PartialTransfer {
12 pub fn new(shard_dir: &Path, commit_id: &str) -> Result<Self> {
13 let dir = shard_dir.join("partial").join(commit_id);
14 fs::create_dir_all(&dir)?;
15 Ok(Self {
16 dir,
17 commit_id: commit_id.to_string(),
18 })
19 }
20
21 pub fn has_chunk(&self, chunk_id: &str) -> bool {
22 self.dir.join(chunk_id).exists()
23 }
24
25 pub fn save_chunk(&self, chunk_id: &str, data: &[u8]) -> Result<()> {
26 fs::write(self.dir.join(chunk_id), data)?;
27 Ok(())
28 }
29
30 pub fn load_chunk(&self, chunk_id: &str) -> Result<Vec<u8>> {
31 Ok(fs::read(self.dir.join(chunk_id))?)
32 }
33
34 pub fn remove_chunk(&self, chunk_id: &str) -> Result<()> {
35 let path = self.dir.join(chunk_id);
36 if path.exists() {
37 fs::remove_file(path)?;
38 }
39 Ok(())
40 }
41
42 pub fn list_chunks(&self) -> Result<Vec<String>> {
43 let mut ids = Vec::new();
44 if self.dir.exists() {
45 for entry in fs::read_dir(&self.dir)? {
46 let entry = entry?;
47 if entry.file_type()?.is_file() {
48 ids.push(entry.file_name().to_string_lossy().to_string());
49 }
50 }
51 }
52 Ok(ids)
53 }
54
55 pub fn cleanup(&self) -> Result<()> {
56 if self.dir.exists() {
57 fs::remove_dir_all(&self.dir)?;
58 }
59 Ok(())
60 }
61}
62
63pub fn list_incomplete_transfers(shard_dir: &Path) -> Result<Vec<String>> {
64 let partial_dir = shard_dir.join("partial");
65 if !partial_dir.exists() {
66 return Ok(Vec::new());
67 }
68 let mut transfers = Vec::new();
69 for entry in fs::read_dir(&partial_dir)? {
70 let entry = entry?;
71 if entry.file_type()?.is_dir() {
72 transfers.push(entry.file_name().to_string_lossy().to_string());
73 }
74 }
75 Ok(transfers)
76}
77
78pub fn remove_transfer(shard_dir: &Path, commit_id: &str) -> Result<()> {
79 let partial_dir = shard_dir.join("partial").join(commit_id);
80 if partial_dir.exists() {
81 fs::remove_dir_all(&partial_dir)?;
82 }
83 Ok(())
84}