1use async_trait::async_trait;
4use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6use std::sync::Arc;
7use tokio::sync::RwLock;
8use uuid::Uuid;
9
10use crate::error::Result;
11use crate::manager::{ManagedState, Manager, ManagerStatus, PlatformRequirements};
12
13#[cfg(not(target_arch = "wasm32"))]
14pub mod native;
15#[cfg(target_arch = "wasm32")]
16pub mod web;
17
18pub mod database;
19pub mod filesystem;
20pub mod network;
21pub mod storage;
22
23use crate::platform::database::DatabaseArc;
25use crate::platform::filesystem::FileSystemArc;
26use crate::platform::network::NetworkArc;
27use crate::platform::storage::StorageArc;
28use crate::Error;
29pub use database::{DatabaseProvider, Migration, QueryResult, Row, Transaction};
30pub use filesystem::{FileInfo, FileMetadata, FileSystemProvider};
31pub use network::{NetworkProvider, NetworkRequest, NetworkResponse};
32pub use storage::StorageProvider;
33
34#[derive(Debug, Clone, Serialize, Deserialize)]
36pub struct PlatformCapabilities {
37 pub has_filesystem: bool,
38 pub has_database: bool,
39 pub has_background_tasks: bool,
40 pub has_push_notifications: bool,
41 pub has_biometric_auth: bool,
42 pub has_camera: bool,
43 pub has_location: bool,
44 pub max_file_size: Option<u64>,
45 pub supported_formats: Vec<String>,
46 pub platform_name: String,
47 pub platform_version: String,
48}
49
50impl Default for PlatformCapabilities {
51 fn default() -> Self {
52 Self {
53 has_filesystem: false,
54 has_database: false,
55 has_background_tasks: false,
56 has_push_notifications: false,
57 has_biometric_auth: false,
58 has_camera: false,
59 has_location: false,
60 max_file_size: None,
61 supported_formats: Vec::new(),
62 platform_name: "unknown".to_string(),
63 platform_version: "unknown".to_string(),
64 }
65 }
66}
67
68pub struct PlatformManager {
70 state: ManagedState,
71 filesystem: FileSystemArc,
72 database: DatabaseArc,
73 network: NetworkArc,
74 storage: StorageArc,
75 capabilities: PlatformCapabilities,
76}
77
78impl std::fmt::Debug for PlatformManager {
79 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
80 f.debug_struct("PlatformManager")
81 .field("capabilities", &self.capabilities)
82 .finish()
83 }
84}
85
86impl PlatformManager {
87 pub fn new() -> Result<Self> {
89 let capabilities = Self::detect_capabilities();
90
91 #[cfg(not(target_arch = "wasm32"))]
92 let providers = native::create_providers()?;
93
94 #[cfg(target_arch = "wasm32")]
95 let providers = web::create_providers()?;
96
97 Ok(Self {
98 state: ManagedState::new(Uuid::new_v4(), "platform_manager"),
99 filesystem: providers.filesystem,
100 database: providers.database,
101 network: providers.network,
102 storage: providers.storage,
103 capabilities,
104 })
105 }
106
107 pub fn detect_capabilities() -> PlatformCapabilities {
109 #[cfg(not(target_arch = "wasm32"))]
110 return native::detect_capabilities();
111
112 #[cfg(target_arch = "wasm32")]
113 return web::detect_capabilities();
114 }
115
116 pub fn capabilities(&self) -> &PlatformCapabilities {
118 &self.capabilities
119 }
120
121 pub fn filesystem(&self) -> &dyn FileSystemProvider {
123 self.filesystem.as_ref()
124 }
125 pub fn filesystem_arc(&self) -> FileSystemArc {
126 Arc::clone(&self.filesystem)
127 }
128
129 pub fn database(&self) -> &dyn DatabaseProvider {
131 self.database.as_ref()
132 }
133 pub fn database_arc(&self) -> DatabaseArc {
134 Arc::clone(&self.database)
135 }
136
137 pub fn network(&self) -> &dyn NetworkProvider {
139 self.network.as_ref()
140 }
141
142 pub fn storage(&self) -> &dyn StorageProvider {
144 self.storage.as_ref()
145 }
146}
147
148#[cfg(not(target_arch = "wasm32"))]
149#[async_trait]
150impl Manager for PlatformManager {
151 fn name(&self) -> &str {
152 "platform_manager"
153 }
154
155 fn id(&self) -> Uuid {
156 self.state.id()
157 }
158
159 async fn initialize(&mut self) -> Result<()> {
160 self.state
161 .set_state(crate::manager::ManagerState::Initializing)
162 .await;
163
164 #[cfg(not(target_arch = "wasm32"))]
166 native::initialize().await?;
167
168 #[cfg(target_arch = "wasm32")]
169 web::initialize().await?;
170
171 self.state
172 .set_state(crate::manager::ManagerState::Running)
173 .await;
174 Ok(())
175 }
176
177 async fn shutdown(&mut self) -> Result<()> {
178 self.state
179 .set_state(crate::manager::ManagerState::ShuttingDown)
180 .await;
181
182 #[cfg(not(target_arch = "wasm32"))]
184 native::cleanup().await?;
185
186 #[cfg(target_arch = "wasm32")]
187 web::cleanup().await?;
188
189 self.state
190 .set_state(crate::manager::ManagerState::Shutdown)
191 .await;
192 Ok(())
193 }
194
195 async fn status(&self) -> ManagerStatus {
196 let mut status = self.state.status().await;
197 status.add_metadata(
198 "platform",
199 serde_json::json!(self.capabilities.platform_name),
200 );
201 status.add_metadata(
202 "capabilities",
203 serde_json::to_value(&self.capabilities).unwrap_or_default(),
204 );
205 status
206 }
207
208 fn platform_requirements(&self) -> PlatformRequirements {
209 PlatformRequirements {
210 requires_filesystem: true,
211 requires_network: true,
212 requires_database: true,
213 requires_native_apis: false,
214 minimum_permissions: vec!["platform.access".to_string()],
215 }
216 }
217}
218
219#[cfg(target_arch = "wasm32")]
220#[async_trait(?Send)]
221impl Manager for PlatformManager {
222 fn name(&self) -> &str {
223 "platform_manager"
224 }
225
226 fn id(&self) -> Uuid {
227 self.state.id()
228 }
229
230 async fn initialize(&mut self) -> Result<()> {
231 self.state
232 .set_state(crate::manager::ManagerState::Initializing)
233 .await;
234
235 #[cfg(not(target_arch = "wasm32"))]
237 native::initialize().await?;
238
239 #[cfg(target_arch = "wasm32")]
240 web::initialize().await?;
241
242 self.state
243 .set_state(crate::manager::ManagerState::Running)
244 .await;
245 Ok(())
246 }
247
248 async fn shutdown(&mut self) -> Result<()> {
249 self.state
250 .set_state(crate::manager::ManagerState::ShuttingDown)
251 .await;
252
253 #[cfg(not(target_arch = "wasm32"))]
255 native::cleanup().await?;
256
257 #[cfg(target_arch = "wasm32")]
258 web::cleanup().await?;
259
260 self.state
261 .set_state(crate::manager::ManagerState::Shutdown)
262 .await;
263 Ok(())
264 }
265
266 async fn status(&self) -> ManagerStatus {
267 let mut status = self.state.status().await;
268 status.add_metadata(
269 "platform",
270 serde_json::json!(self.capabilities.platform_name),
271 );
272 status.add_metadata(
273 "capabilities",
274 serde_json::to_value(&self.capabilities).unwrap_or_default(),
275 );
276 status
277 }
278
279 fn platform_requirements(&self) -> PlatformRequirements {
280 PlatformRequirements {
281 requires_filesystem: true,
282 requires_network: true,
283 requires_database: true,
284 requires_native_apis: false,
285 minimum_permissions: vec!["platform.access".to_string()],
286 }
287 }
288}
289
290pub struct PlatformProviders {
292 pub filesystem: FileSystemArc,
293 pub database: DatabaseArc,
294 pub network: NetworkArc,
295 pub storage: StorageArc,
296}
297
298#[derive(Debug, Default)]
300pub struct MockFileSystem {
301 files: Arc<RwLock<HashMap<String, Vec<u8>>>>,
302}
303
304impl MockFileSystem {
305 pub fn new() -> Self {
306 Self {
307 files: Arc::new(RwLock::new(HashMap::new())),
308 }
309 }
310}
311
312impl filesystem::FileSystemBounds for MockFileSystem {}
313
314#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
315#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
316impl FileSystemProvider for MockFileSystem {
317 async fn read_file(&self, path: &str) -> Result<Vec<u8>> {
318 self.files
319 .read()
320 .await
321 .get(path)
322 .cloned()
323 .ok_or_else(|| Error::platform("mock", "filesystem", "File not found"))
324 }
325
326 async fn write_file(&self, path: &str, data: &[u8]) -> Result<()> {
327 self.files
328 .write()
329 .await
330 .insert(path.to_string(), data.to_vec());
331 Ok(())
332 }
333
334 async fn delete_file(&self, path: &str) -> Result<()> {
335 self.files.write().await.remove(path);
336 Ok(())
337 }
338
339 async fn list_directory(&self, _path: &str) -> Result<Vec<FileInfo>> {
340 Ok(Vec::new())
341 }
342
343 async fn create_directory(&self, _path: &str) -> Result<()> {
344 Ok(())
345 }
346
347 async fn file_exists(&self, path: &str) -> bool {
348 self.files.read().await.contains_key(path)
349 }
350
351 async fn get_metadata(&self, _path: &str) -> Result<FileMetadata> {
352 Ok(FileMetadata {
353 size: 0,
354 is_directory: false,
355 is_readonly: false,
356 created: None,
357 modified: chrono::Utc::now(),
358 accessed: None,
359 })
360 }
361}