Skip to main content

alun_fs/
plugin.rs

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
10/// 文件存储操作结果类型
11pub type StoreResult<T> = Result<T, String>;
12
13/// 文件元数据
14#[derive(Debug, Clone, Serialize, Deserialize)]
15pub struct FileMeta {
16    /// UUID v4 文件唯一标识
17    pub file_id: String,
18    /// 原始文件名(含扩展名)
19    pub original_name: String,
20    /// 存储相对路径
21    pub stored_path: String,
22    /// 文件大小(字节)
23    pub size: u64,
24    /// MIME 类型(如 `image/png`)
25    pub content_type: String,
26    /// 创建时间
27    pub created_at: DateTime<Utc>,
28}
29
30/// 文件存储后端枚举
31#[derive(Clone)]
32pub enum FsBackend {
33    /// 本地文件系统
34    Local(Arc<LocalFs>),
35}
36
37/// 文件存储插件(实现 `alun_core::Plugin`,可注册到 PluginManager)
38pub struct FsPlugin {
39    /// 存储后端
40    backend: FsBackend,
41}
42
43impl FsPlugin {
44    /// 创建本地文件存储插件
45    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    /// 获取文件存储后端引用
53    pub fn backend(&self) -> &FsBackend { &self.backend }
54
55    /// 获取本地文件系统引用(仅 Local 后端有效)
56    pub fn local(&self) -> Option<&Arc<LocalFs>> {
57        match &self.backend {
58            FsBackend::Local(fs) => Some(fs),
59        }
60    }
61
62    /// 写入文件(自动按日期和 UUID 命名)
63    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    /// 读取文件内容
70    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    /// 删除文件(不存在不报错)
77    pub async fn delete(&self, path: &str) -> StoreResult<()> {
78        match &self.backend {
79            FsBackend::Local(fs) => fs.delete(path).await,
80        }
81    }
82
83    /// 检查文件是否存在
84    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}