#[allow(unused_imports)]
use super::*;
impl UploadSession {
pub fn is_expired(&self) -> bool {
self.expires_at <= Utc::now()
}
pub fn add_part(&mut self, part_number: i32, etag: String) -> Result<(), UploadError> {
if self.is_expired() {
return Err(UploadError::ValidationFailed("Upload session has expired".to_string()));
}
if self.completed_parts.contains(&part_number) {
return Err(UploadError::Conflict(format!("Part {} already uploaded", part_number)));
}
if self.uploaded_chunks >= self.total_chunks {
return Err(UploadError::ValidationFailed("All chunks already uploaded".to_string()));
}
self.completed_parts.push(part_number);
self.uploaded_chunks += 1;
let etags = self.part_etags.get_or_insert_with(|| serde_json::json!({}));
if let Some(obj) = etags.as_object_mut() {
obj.insert(part_number.to_string(), serde_json::Value::String(etag));
}
self.status = UploadStatus::Uploading;
self.metadata.updated_at = Some(Utc::now());
Ok(())
}
pub fn is_complete(&self) -> bool {
self.uploaded_chunks >= self.total_chunks
}
pub fn calculate_progress(&self) -> i32 {
if self.total_chunks <= 0 {
return 0;
}
((self.uploaded_chunks as f64 / self.total_chunks as f64) * 100.0) as i32
}
pub fn remaining_chunks(&self) -> i32 {
(self.total_chunks - self.uploaded_chunks).max(0)
}
pub fn can_resume(&self) -> bool {
if self.is_expired() {
return false;
}
matches!(self.status, UploadStatus::Initiated | UploadStatus::Uploading)
}
pub fn mark_complete(&mut self) -> Result<(), UploadError> {
if !self.is_complete() {
return Err(UploadError::ValidationFailed(
format!("Upload not complete: {}/{} chunks uploaded", self.uploaded_chunks, self.total_chunks),
));
}
self.status = UploadStatus::Completed;
self.metadata.updated_at = Some(Utc::now());
Ok(())
}
pub fn mark_failed(&mut self, error: String) -> Result<(), UploadError> {
self.status = UploadStatus::Failed;
let etags = self.part_etags.get_or_insert_with(|| serde_json::json!({}));
if let Some(obj) = etags.as_object_mut() {
obj.insert("_error".to_string(), serde_json::Value::String(error));
}
self.metadata.updated_at = Some(Utc::now());
Ok(())
}
pub fn check_invariants(&self) -> Result<(), Vec<&'static str>> {
let mut errors = Vec::new();
if self.uploaded_chunks > self.total_chunks {
errors.push("uploaded_chunks must not exceed total_chunks");
}
if self.uploaded_chunks != self.completed_parts.len() as i32 {
errors.push("uploaded_chunks must equal completed_parts length");
}
if self.file_size <= 0 {
errors.push("file_size must be greater than 0");
}
if self.total_chunks <= 0 {
errors.push("total_chunks must be greater than 0");
}
if self.chunk_size < 5 * 1024 * 1024 {
errors.push("chunk_size must be at least 5MB (5242880 bytes)");
}
if errors.is_empty() { Ok(()) } else { Err(errors) }
}
}