1use crate::types::AiLibError;
2use std::fs;
3use std::io;
4use std::path::{Path, PathBuf};
5use std::time::{SystemTime, UNIX_EPOCH};
6
7pub fn save_temp_file(prefix: &str, bytes: &[u8]) -> io::Result<PathBuf> {
17 let mut dir = std::env::temp_dir();
18 let ts = SystemTime::now()
19 .duration_since(UNIX_EPOCH)
20 .map(|d| d.as_nanos())
21 .unwrap_or(0);
22 let filename = format!("{}-{}.bin", prefix, ts);
23 dir.push(filename);
24 fs::write(&dir, bytes)?;
25 Ok(dir)
26}
27
28pub fn read_file(path: &Path) -> io::Result<Vec<u8>> {
30 fs::read(path)
31}
32
33pub fn remove_file(path: &Path) -> io::Result<()> {
35 fs::remove_file(path)
36}
37
38pub fn guess_mime_from_path(path: &Path) -> &'static str {
40 if let Some(ext) = path.extension().and_then(|s| s.to_str()) {
41 match ext.to_ascii_lowercase().as_str() {
42 "png" => "image/png",
43 "jpg" => "image/jpeg",
44 "jpeg" => "image/jpeg",
45 "gif" => "image/gif",
46 "webp" => "image/webp",
47 "mp3" => "audio/mpeg",
48 "wav" => "audio/wav",
49 "ogg" => "audio/ogg",
50 "mp4" => "video/mp4",
51 "avi" => "video/x-msvideo",
52 "mov" => "video/quicktime",
53 "pdf" => "application/pdf",
54 "txt" => "text/plain",
55 "md" => "text/markdown",
56 "json" => "application/json",
57 "xml" => "application/xml",
58 "html" => "text/html",
59 "css" => "text/css",
60 "js" => "application/javascript",
61 "zip" => "application/zip",
62 "tar" => "application/x-tar",
63 "gz" => "application/gzip",
64 _ => "application/octet-stream",
65 }
66 } else {
67 "application/octet-stream"
68 }
69}
70
71pub fn validate_file(path: &Path) -> Result<(), AiLibError> {
73 if !path.exists() {
74 return Err(AiLibError::FileError(format!(
75 "File does not exist: {}",
76 path.display()
77 )));
78 }
79
80 if !path.is_file() {
81 return Err(AiLibError::FileError(format!(
82 "Path is not a file: {}",
83 path.display()
84 )));
85 }
86
87 fs::metadata(path)
89 .map_err(|e| AiLibError::FileError(format!("Cannot read file metadata: {}", e)))?;
90
91 Ok(())
92}
93
94pub fn get_file_size(path: &Path) -> Result<u64, AiLibError> {
96 let metadata = fs::metadata(path)
97 .map_err(|e| AiLibError::FileError(format!("Cannot read file metadata: {}", e)))?;
98 Ok(metadata.len())
99}
100
101pub fn create_temp_dir(prefix: &str) -> io::Result<PathBuf> {
103 let mut dir = std::env::temp_dir();
104 let ts = SystemTime::now()
105 .duration_since(UNIX_EPOCH)
106 .map(|d| d.as_nanos())
107 .unwrap_or(0);
108 let dirname = format!("{}-{}", prefix, ts);
109 dir.push(dirname);
110 fs::create_dir(&dir)?;
111 Ok(dir)
112}
113
114pub fn is_image_file(path: &Path) -> bool {
116 if let Some(ext) = path.extension().and_then(|s| s.to_str()) {
117 matches!(
118 ext.to_ascii_lowercase().as_str(),
119 "png" | "jpg" | "jpeg" | "gif" | "webp" | "bmp" | "tiff" | "svg"
120 )
121 } else {
122 false
123 }
124}
125
126pub fn is_audio_file(path: &Path) -> bool {
128 if let Some(ext) = path.extension().and_then(|s| s.to_str()) {
129 matches!(
130 ext.to_ascii_lowercase().as_str(),
131 "mp3" | "wav" | "ogg" | "flac" | "aac" | "m4a" | "wma"
132 )
133 } else {
134 false
135 }
136}
137
138pub fn is_video_file(path: &Path) -> bool {
140 if let Some(ext) = path.extension().and_then(|s| s.to_str()) {
141 matches!(
142 ext.to_ascii_lowercase().as_str(),
143 "mp4" | "avi" | "mov" | "wmv" | "flv" | "mkv" | "webm" | "m4v"
144 )
145 } else {
146 false
147 }
148}
149
150pub fn is_text_file(path: &Path) -> bool {
152 if let Some(ext) = path.extension().and_then(|s| s.to_str()) {
153 matches!(
154 ext.to_ascii_lowercase().as_str(),
155 "txt"
156 | "md"
157 | "json"
158 | "xml"
159 | "html"
160 | "css"
161 | "js"
162 | "rs"
163 | "py"
164 | "java"
165 | "cpp"
166 | "c"
167 )
168 } else {
169 false
170 }
171}
172
173pub fn get_file_extension(path: &Path) -> Option<String> {
175 path.extension()
176 .and_then(|s| s.to_str())
177 .map(|s| s.to_ascii_lowercase())
178}
179
180pub fn is_file_size_acceptable(path: &Path, max_size_mb: u64) -> Result<bool, AiLibError> {
182 let size = get_file_size(path)?;
183 let max_size_bytes = max_size_mb * 1024 * 1024;
184 Ok(size <= max_size_bytes)
185}