package filesystem import ( "context" "fmt" "os" "os/exec" "path/filepath" "runtime" "sync" "time" ) // FileSystemService 文件系统服务 // 统一管理所有文件系统相关的功能,使用依赖注入而非全局变量 type FileSystemService struct { // 核心组件 config *Config pathValidator PathValidator fileTypeManager FileTypeManager // 基础设施组件 auditLogger *AuditLogger recycleBin *RecycleBin lockChecker *FileLockChecker // 状态管理 mu sync.RWMutex initialized bool } // NewFileSystemService 创建新的文件系统服务 // 使用依赖注入,所有组件通过参数传入,便于测试和替换 func NewFileSystemService(config *Config) (*FileSystemService, error) { if config == nil { config = DefaultConfig() } service := &FileSystemService{ config: config, pathValidator: NewPathValidator(config), fileTypeManager: NewFileTypeManager(config), } // 初始化基础设施组件 if err := service.initializeComponents(); err != nil { return nil, fmt.Errorf("初始化文件系统服务失败: %w", err) } service.initialized = true return service, nil } // initializeComponents 初始化各个组件 func (s *FileSystemService) initializeComponents() error { // 1. 初始化审计日志 if s.config.Features.AuditLog { if err := s.initAuditLogger(); err != nil { return fmt.Errorf("初始化审计日志失败: %w", err) } } // 2. 初始化回收站 if s.config.Features.RecycleBin { if err := s.initRecycleBin(); err != nil { return fmt.Errorf("初始化回收站失败: %w", err) } } // 3. 初始化文件锁检查器 if s.config.Features.FileLockCheck { s.lockChecker = NewFileLockChecker() } return nil } // initAuditLogger 初始化审计日志 func (s *FileSystemService) initAuditLogger() error { // 获取日志目录 userDataDir := getUserDataDir() logDir := filepath.Join(userDataDir, "logs") logger, err := NewAuditLogger(logDir) if err != nil { return err } s.auditLogger = logger return nil } // initRecycleBin 初始化回收站 func (s *FileSystemService) initRecycleBin() error { // 获取回收站目录 userDataDir := getUserDataDir() recycleBinPath := filepath.Join(userDataDir, "recycle_bin") bin, err := NewRecycleBin(recycleBinPath) if err != nil { return err } s.recycleBin = bin return nil } // ========== 核心文件操作 ========== // Read 读取文件内容(实现 FileService 接口) func (s *FileSystemService) Read(path string) (string, error) { return s.ReadFile(path) } // ReadFile 读取文件内容 func (s *FileSystemService) ReadFile(path string) (string, error) { // 路径验证 if err := s.validatePath(path); err != nil { return "", err } // 读取文件 data, err := os.ReadFile(path) if err != nil { return "", fmt.Errorf("读取文件失败: %v", err) } // 记录审计日志 if s.auditLogger != nil { s.auditLogger.LogRead(path, int64(len(data)), nil) } return string(data), nil } // Write 写入文件内容(实现 FileService 接口) func (s *FileSystemService) Write(path, content string) error { return s.WriteFile(path, content) } // WriteFile 写入文件 func (s *FileSystemService) WriteFile(path, content string) error { // 路径验证 if err := s.validatePath(path); err != nil { return err } // 创建目录 dir := filepath.Dir(path) if err := os.MkdirAll(dir, DefaultDirPermissions); err != nil { return fmt.Errorf("创建目录失败: %v", err) } // 写入文件 data := []byte(content) if err := os.WriteFile(path, data, DefaultFilePermissions); err != nil { // 记录审计日志 if s.auditLogger != nil { s.auditLogger.LogWrite(path, int64(len(data)), err) } return fmt.Errorf("写入文件失败: %v", err) } // 记录审计日志 if s.auditLogger != nil { s.auditLogger.LogWrite(path, int64(len(data)), nil) } return nil } // List 列出目录内容(实现 FileService 接口) func (s *FileSystemService) List(path string) ([]map[string]interface{}, error) { return s.ListDir(path) } // Open 打开文件(实现 FileService 接口) func (s *FileSystemService) Open(path string) error { // 使用系统默认程序打开文件 var cmd *exec.Cmd switch runtime.GOOS { case "windows": cmd = exec.Command("cmd", "/c", "start", "", path) case "darwin": cmd = exec.Command("open", path) default: cmd = exec.Command("xdg-open", path) } return cmd.Start() } // Delete 删除文件或目录(实现 FileService 接口) func (s *FileSystemService) Delete(path string) error { return s.DeletePathWithContext(context.Background(), path) } // DeletePath 删除文件或目录 func (s *FileSystemService) DeletePath(path string) error { return s.DeletePathWithContext(context.Background(), path) } // DeletePathWithContext 带上下文的删除操作 func (s *FileSystemService) DeletePathWithContext(ctx context.Context, path string) error { // 路径验证 if err := s.validatePath(path); err != nil { return err } // 获取文件信息 info, err := os.Stat(path) if err != nil { if os.IsNotExist(err) { return fmt.Errorf("文件或目录不存在") } return fmt.Errorf("获取文件信息失败: %v", err) } // 检查删除限制 exceeds, details, checkErr := CheckDeleteRestrictions(path, info, s.config) if checkErr != nil { return checkErr } if exceeds { if s.config.Security.DeleteRestrictions.RequireConfirm { return &DeleteRestrictionWarning{ Path: path, Details: details, Info: info, } } return fmt.Errorf("删除限制: %s", details) } // 文件锁检查(可选) if s.lockChecker != nil { if err := s.lockChecker.SafeDeleteWithLockCheck(path); err != nil { return err } } // 执行删除 var deleteErr error if info.IsDir() { deleteErr = os.RemoveAll(path) } else { deleteErr = os.Remove(path) } // 记录审计日志 if s.auditLogger != nil { s.auditLogger.LogDelete(path, info.IsDir(), info.Size(), deleteErr) } if deleteErr != nil { return fmt.Errorf("删除失败: %v", deleteErr) } // 如果启用回收站,移动到回收站而非永久删除 if s.recycleBin != nil { // 检查是否已在回收站中 if !isInRecycleBin(path) { if err := s.recycleBin.MoveToRecycleBin(path); err != nil { // 回收站失败,记录但继续 fmt.Printf("[警告] 移动到回收站失败: %v\n", err) } } } return nil } // ListDir 列出目录内容 func (s *FileSystemService) ListDir(path string) ([]map[string]interface{}, error) { // 路径验证 if err := s.validatePath(path); err != nil { return nil, err } // 读取目录 entries, err := os.ReadDir(path) if err != nil { return nil, fmt.Errorf("读取目录失败: %v", err) } // 转换为结果格式 result := make([]map[string]interface{}, 0, len(entries)) for _, entry := range entries { info, err := entry.Info() if err != nil { continue } fullPath := filepath.Join(path, entry.Name()) result = append(result, map[string]interface{}{ "name": entry.Name(), "path": fullPath, "is_dir": entry.IsDir(), "size": info.Size(), "mod_time": info.ModTime().Format("2006-01-02 15:04:05"), }) } // 记录审计日志 if s.auditLogger != nil { s.auditLogger.Log(AuditLogEntry{ Timestamp: getCurrentTimestamp(), Operation: OperationList, Path: path, IsDirectory: true, Success: true, }) } return result, nil } // CreateDir 创建目录 func (s *FileSystemService) CreateDir(path string) error { if err := s.validatePath(path); err != nil { return err } if err := os.MkdirAll(path, DefaultDirPermissions); err != nil { return fmt.Errorf("创建目录失败: %v", err) } // 记录审计日志 if s.auditLogger != nil { s.auditLogger.Log(AuditLogEntry{ Timestamp: getCurrentTimestamp(), Operation: OperationCreate, Path: path, IsDirectory: true, Success: true, }) } return nil } // CreateFile 创建空文件 func (s *FileSystemService) CreateFile(path string) error { if err := s.validatePath(path); err != nil { return err } // 检查文件是否已存在 if _, err := os.Stat(path); err == nil { return fmt.Errorf("文件已存在") } file, err := os.Create(path) if err != nil { return fmt.Errorf("创建文件失败: %v", err) } file.Close() // 记录审计日志 if s.auditLogger != nil { s.auditLogger.Log(AuditLogEntry{ Timestamp: getCurrentTimestamp(), Operation: OperationCreate, Path: path, IsDirectory: false, Success: true, }) } return nil } // GetInfo 获取文件信息(实现 FileService 接口) func (s *FileSystemService) GetInfo(path string) (map[string]interface{}, error) { return s.GetFileInfo(path) } // GetFileInfo 获取文件信息 func (s *FileSystemService) GetFileInfo(path string) (map[string]interface{}, error) { if err := s.validatePath(path); err != nil { return nil, err } info, err := os.Stat(path) if err != nil { if os.IsNotExist(err) { return nil, fmt.Errorf("文件或目录不存在") } return nil, fmt.Errorf("获取文件信息失败: %v", err) } return map[string]interface{}{ "name": info.Name(), "path": path, "size": info.Size(), "size_str": formatBytes(info.Size()), "is_dir": info.IsDir(), "mod_time": info.ModTime().Format("2006-01-02 15:04:05"), "mode": info.Mode().String(), }, nil } // OpenPath 打开文件或目录(使用系统默认程序) func (s *FileSystemService) OpenPath(path string) error { if err := s.validatePath(path); err != nil { return err } return OpenPath(path) } // ========== ZIP操作接口 ========== // ListZip 列出ZIP文件内容 func (s *FileSystemService) ListZip(zipPath string) ([]map[string]interface{}, error) { return ListZipContents(zipPath) } // ExtractZipFile 从ZIP提取文件内容 func (s *FileSystemService) ExtractZipFile(zipPath, filePath string) (string, error) { return ExtractFileFromZip(zipPath, filePath) } // ExtractZipFileToTemp 从ZIP提取文件到临时目录 func (s *FileSystemService) ExtractZipFileToTemp(zipPath, filePath string) (string, error) { return ExtractFileFromZipToTemp(zipPath, filePath) } // GetZipFileInfo 获取ZIP文件信息 func (s *FileSystemService) GetZipFileInfo(zipPath, filePath string) (map[string]interface{}, error) { return GetZipFileInfo(zipPath, filePath) } // ========== 辅助函数 ========== // getUserDataDir 获取用户数据目录 func getUserDataDir() string { var basePath string switch runtime.GOOS { case "windows": basePath = os.Getenv("LOCALAPPDATA") if basePath == "" { basePath = os.Getenv("APPDATA") } case "darwin": homeDir, _ := os.UserHomeDir() basePath = filepath.Join(homeDir, "Library", "Application Support") default: homeDir, _ := os.UserHomeDir() basePath = filepath.Join(homeDir, ".config") } if basePath == "" { basePath = "." } return filepath.Join(basePath, "u-desk") } // getCurrentTimestamp 获取当前时间戳 func getCurrentTimestamp() time.Time { return time.Now() } // isInRecycleBin 检查路径是否在回收站中 func isInRecycleBin(path string) bool { // 简化版本:检查路径是否包含回收站目录名 userDataDir := getUserDataDir() recycleBinPath := filepath.Join(userDataDir, "recycle_bin") return filepath.HasPrefix(filepath.Clean(path), filepath.Clean(recycleBinPath)) } // ========== 辅助方法 ========== // validatePath 验证路径 func (s *FileSystemService) validatePath(path string) error { err := s.pathValidator.Validate(path) if err != nil && err.IsError { return err } return nil } // GetConfig 获取配置 func (s *FileSystemService) GetConfig() *Config { return s.config } // GetAuditLogger 获取审计日志记录器 func (s *FileSystemService) GetAuditLogger() *AuditLogger { return s.auditLogger } // GetRecycleBin 获取回收站 func (s *FileSystemService) GetRecycleBin() *RecycleBin { return s.recycleBin } // Close 关闭服务,释放资源 func (s *FileSystemService) Close(ctx context.Context) error { s.mu.Lock() defer s.mu.Unlock() if !s.initialized { return nil } // 关闭审计日志 if s.auditLogger != nil { if err := s.auditLogger.Close(); err != nil { return fmt.Errorf("关闭审计日志失败: %w", err) } } s.initialized = false return nil } // ========== 全局服务实例(向后兼容)========== var ( globalService *FileSystemService globalServiceOnce sync.Once ) // GetGlobalService 获取全局文件系统服务实例(单例) // 保持向后兼容,但推荐使用依赖注入 func GetGlobalService() (*FileSystemService, error) { var initErr error globalServiceOnce.Do(func() { globalService, initErr = NewFileSystemService(DefaultConfig()) }) return globalService, initErr } // InitGlobalFileSystem 初始化全局文件系统(兼容旧代码) func InitGlobalFileSystem() error { _, err := GetGlobalService() return err } // CloseGlobalFileSystem 关闭全局文件系统 func CloseGlobalFileSystem(ctx context.Context) error { if globalService != nil { return globalService.Close(ctx) } return nil }