1use alun_core::plugin::Plugin;
2use async_trait::async_trait;
3use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5use std::sync::Arc;
6use tracing::info;
7
8use super::local::LocalFs;
9
10pub type StoreResult<T> = Result<T, String>;
12
13#[derive(Debug, Clone, Serialize, Deserialize)]
15pub struct FileMeta {
16 pub file_id: String,
18 pub original_name: String,
20 pub stored_path: String,
22 pub size: u64,
24 pub content_type: String,
26 pub created_at: DateTime<Utc>,
28}
29
30#[derive(Clone)]
32pub enum FsBackend {
33 Local(Arc<LocalFs>),
35}
36
37pub struct FsPlugin {
39 backend: FsBackend,
41}
42
43impl FsPlugin {
44 pub fn new_local(root_dir: &str) -> Self {
46 let fs = LocalFs::new(root_dir);
47 Self {
48 backend: FsBackend::Local(Arc::new(fs)),
49 }
50 }
51
52 pub fn backend(&self) -> &FsBackend { &self.backend }
54
55 pub fn local(&self) -> Option<&Arc<LocalFs>> {
57 match &self.backend {
58 FsBackend::Local(fs) => Some(fs),
59 }
60 }
61
62 pub async fn write(&self, filename: &str, data: &[u8]) -> StoreResult<FileMeta> {
64 match &self.backend {
65 FsBackend::Local(fs) => fs.write_with_name(filename, data).await,
66 }
67 }
68
69 pub async fn read(&self, path: &str) -> StoreResult<Vec<u8>> {
71 match &self.backend {
72 FsBackend::Local(fs) => fs.read(path).await,
73 }
74 }
75
76 pub async fn delete(&self, path: &str) -> StoreResult<()> {
78 match &self.backend {
79 FsBackend::Local(fs) => fs.delete(path).await,
80 }
81 }
82
83 pub async fn exists(&self, path: &str) -> bool {
85 match &self.backend {
86 FsBackend::Local(fs) => fs.exists(path).await,
87 }
88 }
89}
90
91#[async_trait]
92impl Plugin for FsPlugin {
93 fn name(&self) -> &str { "fs" }
94
95 async fn start(&self) -> alun_core::Result<()> {
96 info!("FsPlugin 启动 (local)");
97 Ok(())
98 }
99
100 async fn stop(&self) -> alun_core::Result<()> {
101 info!("FsPlugin 停止");
102 Ok(())
103 }
104}