use crate::error::Result;
use crate::models::metadata::JdkMetadata;
use chrono::Utc;
use std::ffi::OsStr;
use std::fs;
use std::path::{Path, PathBuf};
use super::types::{FileState, FileStatus};
pub fn process_metadata_file(
path: &Path,
metadata: &[JdkMetadata],
minify_json: bool,
) -> Result<()> {
let state_path = PathBuf::from(format!("{}.state", path.display()));
let state = FileState {
status: FileStatus::InProgress,
started_at: Utc::now(),
updated_at: Utc::now(),
attempts: 1,
error: None,
checksum: None,
};
fs::write(&state_path, serde_json::to_string(&state)?)?;
let content = if minify_json {
serde_json::to_string(metadata)?
} else {
serde_json::to_string_pretty(metadata)?
};
match fs::write(path, &content) {
Ok(_) => {
let mut state = state;
state.status = FileStatus::Completed;
state.updated_at = Utc::now();
state.checksum = Some(calculate_file_checksum(path)?);
fs::write(&state_path, serde_json::to_string(&state)?)?;
Ok(())
}
Err(e) => {
let mut state = state;
state.status = FileStatus::Failed;
state.error = Some(e.to_string());
state.updated_at = Utc::now();
fs::write(&state_path, serde_json::to_string(&state)?)?;
Err(e.into())
}
}
}
pub fn should_skip_file(json_path: &Path) -> bool {
let state_path = PathBuf::from(format!("{}.state", json_path.display()));
if let Ok(content) = fs::read_to_string(&state_path) {
if let Ok(state) = serde_json::from_str::<FileState>(&content) {
match state.status {
FileStatus::Completed => {
if let Some(checksum) = state.checksum {
if json_path.exists() {
if let Ok(current_checksum) = calculate_file_checksum(json_path) {
return current_checksum == checksum;
}
}
}
false
}
FileStatus::InProgress => {
let age = Utc::now() - state.updated_at;
age.num_hours() > 1
}
FileStatus::Failed => false,
}
} else {
false
}
} else {
false
}
}
pub fn detect_resume_state(output_dir: &Path) -> bool {
use walkdir::WalkDir;
if !output_dir.exists() {
return false;
}
for entry in WalkDir::new(output_dir).max_depth(3).into_iter().flatten() {
let path = entry.path();
if path.extension() == Some(OsStr::new("state")) {
return true;
}
}
false
}
pub fn cleanup_state_files(output_dir: &Path) -> Result<()> {
use walkdir::WalkDir;
for entry in WalkDir::new(output_dir) {
let entry = entry?;
let path = entry.path();
if path.extension() == Some(OsStr::new("state"))
&& path != output_dir.join("index.json.state")
{
fs::remove_file(path)?;
}
}
let index_state = output_dir.join("index.json.state");
if index_state.exists() {
fs::remove_file(index_state)?;
}
Ok(())
}
pub fn calculate_file_checksum(path: &Path) -> Result<String> {
use sha2::{Digest, Sha256};
let content = fs::read(path)?;
let mut hasher = Sha256::new();
hasher.update(&content);
Ok(format!("{:x}", hasher.finalize()))
}
pub fn calculate_sha256(content: &str) -> String {
use sha2::{Digest, Sha256};
let mut hasher = Sha256::new();
hasher.update(content.as_bytes());
format!("{:x}", hasher.finalize())
}