修复: 文件系统初始化守卫与传输收尾等七处
- filesystemSvc 守卫17绑定方法,异步初始化完成前返回明确错误 - MovePath 跨盘剪切建 move emitter,失败清理目标盘残留 - SFTP 空目录下载/上传补 MkdirAll 落地 - drawio 下载失败等待者立即返回,不再空轮询30分钟 - batch 高亮补 %1 与 %%i 规则 - 错误文案转换抽 errMessage 共享函数,11处归一 - log.Printf 统一 slog.Warn
This commit is contained in:
+106
-20
@@ -11,6 +11,15 @@ import (
|
||||
"github.com/wailsapp/wails/v3/pkg/application"
|
||||
)
|
||||
|
||||
// filesystemSvc 返回文件系统服务。初始化在启动 goroutine 异步进行,
|
||||
// 完成前前端触发文件操作时返回明确错误而非 nil panic
|
||||
func (a *App) filesystemSvc() (*filesystem.FileSystemService, error) {
|
||||
if a.filesystem == nil {
|
||||
return nil, fmt.Errorf("文件系统服务尚未初始化完成,请稍后重试")
|
||||
}
|
||||
return a.filesystem, nil
|
||||
}
|
||||
|
||||
// EnsureDrawioViewer 确保本地已缓存 drawio viewer(首次预览时下载),前端打开 .drawio 前调用。
|
||||
// 通过 drawio-download-progress 事件推送下载进度。
|
||||
func (a *App) EnsureDrawioViewer() (map[string]interface{}, error) {
|
||||
@@ -30,7 +39,11 @@ func (a *App) EnsureDrawioViewer() (map[string]interface{}, error) {
|
||||
|
||||
// ReadFile 读取文件
|
||||
func (a *App) ReadFile(path string) (string, error) {
|
||||
return a.filesystem.ReadFile(path)
|
||||
fs, err := a.filesystemSvc()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return fs.ReadFile(path)
|
||||
}
|
||||
|
||||
// WatchFile 开始监听指定文件的变化,变化时发送 file-changed 事件
|
||||
@@ -50,52 +63,93 @@ func (a *App) UnwatchFile() {
|
||||
|
||||
// WriteFile 写入文件
|
||||
func (a *App) WriteFile(req WriteFileRequest) error {
|
||||
return a.filesystem.WriteFile(req.Path, req.Content)
|
||||
fs, err := a.filesystemSvc()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return fs.WriteFile(req.Path, req.Content)
|
||||
}
|
||||
|
||||
// SaveBase64File 将 base64 内容解码后写入文件(用于图片等二进制数据)
|
||||
func (a *App) SaveBase64File(req SaveBase64FileRequest) error {
|
||||
return a.filesystem.SaveBase64File(req.Path, req.Content)
|
||||
fs, err := a.filesystemSvc()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return fs.SaveBase64File(req.Path, req.Content)
|
||||
}
|
||||
|
||||
// ListDir 列出目录
|
||||
func (a *App) ListDir(path string) ([]map[string]interface{}, error) {
|
||||
return a.filesystem.ListDir(path)
|
||||
fs, err := a.filesystemSvc()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return fs.ListDir(path)
|
||||
}
|
||||
|
||||
// CreateDir 创建目录
|
||||
func (a *App) CreateDir(path string) (*filesystem.FileOperationResult, error) {
|
||||
return a.filesystem.CreateDir(path)
|
||||
fs, err := a.filesystemSvc()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return fs.CreateDir(path)
|
||||
}
|
||||
|
||||
// CreateFile 创建文件
|
||||
func (a *App) CreateFile(path string) (*filesystem.FileOperationResult, error) {
|
||||
return a.filesystem.CreateFile(path)
|
||||
fs, err := a.filesystemSvc()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return fs.CreateFile(path)
|
||||
}
|
||||
|
||||
// DeletePath 删除文件或目录
|
||||
func (a *App) DeletePath(path string) (*filesystem.FileOperationResult, error) {
|
||||
return a.filesystem.DeletePath(path)
|
||||
fs, err := a.filesystemSvc()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return fs.DeletePath(path)
|
||||
}
|
||||
|
||||
// RenamePath 重命名文件或目录
|
||||
func (a *App) RenamePath(req RenamePathRequest) (*filesystem.FileOperationResult, error) {
|
||||
return a.filesystem.RenamePath(req.OldPath, req.NewPath)
|
||||
fs, err := a.filesystemSvc()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return fs.RenamePath(req.OldPath, req.NewPath)
|
||||
}
|
||||
|
||||
// CopyPath 复制文件或目录(递归),通过 transfer-progress 事件推送进度
|
||||
func (a *App) CopyPath(src, dst string) error {
|
||||
fs, err := a.filesystemSvc()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
emitter := newTransferEmitter(a, "copy", filepath.Base(filepath.FromSlash(src)))
|
||||
err := a.filesystem.CopyPath(src, dst, func(copied, total int64) {
|
||||
err = fs.CopyPath(src, dst, func(copied, total int64) {
|
||||
emitter.progress(emitter.name, copied, total)
|
||||
})
|
||||
emitter.finish(err)
|
||||
return err
|
||||
}
|
||||
|
||||
// MovePath 移动文件或目录(同盘重命名,跨盘复制后删除)
|
||||
// MovePath 移动文件或目录(同盘重命名,跨盘复制后删除),跨盘时经 transfer-progress 事件推送进度
|
||||
func (a *App) MovePath(src, dst string) error {
|
||||
return a.filesystem.MovePath(src, dst)
|
||||
fs, err := a.filesystemSvc()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
emitter := newTransferEmitter(a, "move", filepath.Base(filepath.FromSlash(src)))
|
||||
err = fs.MovePath(src, dst, func(copied, total int64) {
|
||||
emitter.progress(emitter.name, copied, total)
|
||||
})
|
||||
emitter.finish(err)
|
||||
return err
|
||||
}
|
||||
|
||||
// PickDirectory 打开系统目录选择器,返回选中目录(取消时返回空串)
|
||||
@@ -177,39 +231,67 @@ func (t *transferEmitter) finish(err error) {
|
||||
|
||||
// GetFileInfo 获取文件信息
|
||||
func (a *App) GetFileInfo(path string) (map[string]interface{}, error) {
|
||||
return a.filesystem.GetFileInfo(path)
|
||||
fs, err := a.filesystemSvc()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return fs.GetFileInfo(path)
|
||||
}
|
||||
|
||||
// OpenPath 使用系统默认程序打开文件或目录
|
||||
func (a *App) OpenPath(path string) error {
|
||||
return a.filesystem.OpenPath(path)
|
||||
fs, err := a.filesystemSvc()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return fs.OpenPath(path)
|
||||
}
|
||||
|
||||
// ========== Zip 文件操作接口 ==========
|
||||
|
||||
// ListZipContents 列出 zip 文件内容
|
||||
func (a *App) ListZipContents(zipPath string) ([]map[string]interface{}, error) {
|
||||
return a.filesystem.ListZipContents(zipPath)
|
||||
fs, err := a.filesystemSvc()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return fs.ListZipContents(zipPath)
|
||||
}
|
||||
|
||||
// ExtractFileFromZip 从 zip 文件中提取单个文件内容
|
||||
func (a *App) ExtractFileFromZip(zipPath, filePath string) (string, error) {
|
||||
return a.filesystem.ExtractFileFromZip(zipPath, filePath)
|
||||
fs, err := a.filesystemSvc()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return fs.ExtractFileFromZip(zipPath, filePath)
|
||||
}
|
||||
|
||||
// ExtractFileFromZipToTemp 从 zip 文件中提取单个文件到临时目录
|
||||
func (a *App) ExtractFileFromZipToTemp(zipPath, filePath string) (string, error) {
|
||||
return a.filesystem.ExtractFileFromZipToTemp(zipPath, filePath)
|
||||
fs, err := a.filesystemSvc()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return fs.ExtractFileFromZipToTemp(zipPath, filePath)
|
||||
}
|
||||
|
||||
// GetZipFileInfo 获取 zip 文件中特定文件的信息
|
||||
func (a *App) GetZipFileInfo(zipPath, filePath string) (map[string]interface{}, error) {
|
||||
return a.filesystem.GetZipFileInfo(zipPath, filePath)
|
||||
fs, err := a.filesystemSvc()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return fs.GetZipFileInfo(zipPath, filePath)
|
||||
}
|
||||
|
||||
// ResolveShortcut 解析快捷方式文件,返回目标路径信息
|
||||
func (a *App) ResolveShortcut(lnkPath string) (map[string]interface{}, error) {
|
||||
targetPath, err := a.filesystem.ResolveShortcut(lnkPath)
|
||||
fs, err := a.filesystemSvc()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
targetPath, err := fs.ResolveShortcut(lnkPath)
|
||||
if err != nil {
|
||||
return map[string]interface{}{
|
||||
"success": false,
|
||||
@@ -217,7 +299,7 @@ func (a *App) ResolveShortcut(lnkPath string) (map[string]interface{}, error) {
|
||||
}, err
|
||||
}
|
||||
|
||||
fileInfo, err := a.filesystem.GetFileInfo(targetPath)
|
||||
fileInfo, err := fs.GetFileInfo(targetPath)
|
||||
if err != nil {
|
||||
return map[string]interface{}{
|
||||
"success": true,
|
||||
@@ -284,5 +366,9 @@ func (a *App) initFilesystemModule() {
|
||||
|
||||
// GetAuditLogs 获取审计日志
|
||||
func (a *App) GetAuditLogs(limit int) ([]map[string]interface{}, error) {
|
||||
return a.filesystem.GetAuditLogs(limit)
|
||||
fs, err := a.filesystemSvc()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return fs.GetAuditLogs(limit)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user