1use rew_core::utils;
2use anyhow::{Context, Result};
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5use std::fs;
6use std::io::Read;
7use std::path::{Path, PathBuf};
8pub struct DataManager {
9 data_dir: PathBuf,
10}
11
12#[derive(Serialize, Deserialize, Debug)]
13pub enum DataFormat {
14 Text,
15 Json,
16 Yaml,
17 Binary,
18}
19
20impl DataManager {
21 pub fn new(user_id: &str, app_package: &str) -> Result<Self> {
22 let rew_root = utils::get_rew_root();
23 let data_dir = rew_root.join("data").join(user_id).join(app_package);
24
25 fs::create_dir_all(&data_dir)
27 .with_context(|| format!("Failed to create data directory: {:?}", data_dir))?;
28
29 Ok(Self { data_dir })
30 }
31
32 pub fn get_path(&self, key: &str) -> PathBuf {
33 self.data_dir.join(key)
34 }
35
36 pub fn read(&self, key: &str) -> Result<String> {
37 let path = self.get_path(key);
38 fs::read_to_string(&path).with_context(|| format!("Failed to read data file: {:?}", path))
39 }
40
41 pub fn read_json(&self, key: &str) -> Result<Value> {
42 let content = self.read(key)?;
43 serde_json::from_str(&content)
44 .with_context(|| format!("Failed to parse JSON from data file: {}", key))
45 }
46
47 pub fn write(&self, key: &str, content: &str) -> Result<()> {
48 let path = self.get_path(key);
49
50 if let Some(parent) = path.parent() {
52 fs::create_dir_all(parent)
53 .with_context(|| format!("Failed to create parent directory: {:?}", parent))?;
54 }
55
56 fs::write(&path, content).with_context(|| format!("Failed to write data file: {:?}", path))
57 }
58
59 pub fn write_json(&self, key: &str, value: &Value) -> Result<()> {
60 let content = serde_json::to_string_pretty(value)
61 .with_context(|| format!("Failed to serialize JSON for data file: {}", key))?;
62 self.write(key, &content)
63 }
64
65 pub fn delete(&self, key: &str) -> Result<()> {
66 let path = self.get_path(key);
67 if path.exists() {
68 fs::remove_file(&path).with_context(|| format!("Failed to delete data file: {:?}", path))?;
69 }
70 Ok(())
71 }
72
73 pub fn exists(&self, key: &str) -> bool {
74 self.get_path(key).exists()
75 }
76
77 pub fn list(&self, prefix: &str) -> Result<Vec<String>> {
78 let dir = self.data_dir.join(prefix);
79 if !dir.exists() {
80 return Ok(Vec::new());
81 }
82
83 let mut result = Vec::new();
84 self.list_recursive(&dir, &mut result, prefix)?;
85 Ok(result)
86 }
87
88 fn list_recursive(&self, dir: &Path, result: &mut Vec<String>, _prefix: &str) -> Result<()> {
89 if !dir.exists() {
90 return Ok(());
91 }
92
93 for entry in
94 fs::read_dir(dir).with_context(|| format!("Failed to read directory: {:?}", dir))?
95 {
96 let entry = entry?;
97 let path = entry.path();
98
99 if path.is_file() {
100 let rel_path = path
101 .strip_prefix(&self.data_dir)
102 .unwrap_or(&path)
103 .to_string_lossy()
104 .to_string();
105 result.push(rel_path);
106 } else if path.is_dir() {
107 self.list_recursive(&path, result, _prefix)?;
108 }
109 }
110
111 Ok(())
112 }
113
114 pub fn read_binary(&self, key: &str) -> Result<Vec<u8>> {
116 let path = self.get_path(key);
117 fs::read(&path).with_context(|| format!("Failed to read binary data file: {:?}", path))
118 }
119
120 pub fn write_binary(&self, key: &str, data: &[u8]) -> Result<()> {
122 let path = self.get_path(key);
123
124 if let Some(parent) = path.parent() {
126 fs::create_dir_all(parent)
127 .with_context(|| format!("Failed to create parent directory: {:?}", parent))?;
128 }
129
130 fs::write(&path, data).with_context(|| format!("Failed to write binary data file: {:?}", path))
131 }
132
133 pub fn read_yaml(&self, key: &str) -> Result<Value> {
135 let content = self.read(key)?;
136 serde_yaml::from_str(&content)
137 .with_context(|| format!("Failed to parse YAML from data file: {}", key))
138 }
139
140 pub fn write_yaml(&self, key: &str, value: &Value) -> Result<()> {
142 let content = serde_yaml::to_string(value)
143 .with_context(|| format!("Failed to serialize YAML for data file: {}", key))?;
144 self.write(key, &content)
145 }
146
147 pub fn get_file_info(&self, key: &str) -> Result<(bool, DataFormat)> {
149 let path = self.get_path(key);
150
151 if !path.exists() {
152 return Ok((false, DataFormat::Text)); }
154
155 let format = if let Some(ext) = path.extension() {
157 match ext.to_str().unwrap_or("").to_lowercase().as_str() {
158 "json" => DataFormat::Json,
159 "yaml" | "yml" => DataFormat::Yaml,
160 "bin" | "dat" => DataFormat::Binary,
161 _ => {
162 self.detect_format(&path)?
164 }
165 }
166 } else {
167 self.detect_format(&path)?
169 };
170
171 Ok((true, format))
172 }
173
174 fn detect_format(&self, path: &Path) -> Result<DataFormat> {
176 let mut file = fs::File::open(path)?;
178 let mut buffer = [0u8; 512]; let bytes_read = file.read(&mut buffer)?;
180
181 if bytes_read == 0 {
182 return Ok(DataFormat::Text); }
184
185 let sample = &buffer[..bytes_read];
187 if sample
188 .iter()
189 .any(|&b| b < 9 || (b > 13 && b < 32 && b != 27))
190 {
191 return Ok(DataFormat::Binary);
192 }
193
194 let content = String::from_utf8_lossy(sample);
196 if (content.trim_start().starts_with('{') || content.trim_start().starts_with('['))
197 && serde_json::from_str::<Value>(&content).is_ok()
198 {
199 return Ok(DataFormat::Json);
200 }
201
202 if content.contains(':')
204 && !content.contains('{')
205 && serde_yaml::from_str::<Value>(&content).is_ok()
206 {
207 return Ok(DataFormat::Yaml);
208 }
209
210 Ok(DataFormat::Text)
212 }
213}