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