修复: SFTP连接首拉不显示与传输挂起

- watcher握手期伪触发致幻影本地列表,根因修复
- 连接探测2.5s超时竞速,握手10s预算
- 30s保活自动掐死半开连接,取连接时剔除已断开
- 副本命名与进度计数抽公共,下载缓存清理去重
This commit is contained in:
lxy
2026-09-15 22:26:22 +08:00
parent e7a2c5148e
commit 6ea9d9ac99
9 changed files with 731 additions and 125 deletions
+31 -15
View File
@@ -4,8 +4,10 @@ import (
"crypto/sha256"
"fmt"
"log/slog"
"u-desk/internal/common"
"os"
"path/filepath"
"strings"
"time"
"u-desk/internal/storage/models"
@@ -129,7 +131,7 @@ func DownloadToTempCached(transport, connID, remotePath string, fileSize int64,
// 移动文件到确定性路径
if err := os.Rename(tempPath, deterministicPath); err != nil {
// Rename 可能跨卷失败,尝试 Copy+Delete
if copyFile(tempPath, deterministicPath) != nil {
if common.CopyFile(tempPath, deterministicPath) != nil {
SaveCache(transport, connID, remotePath, fileSize, modTime, tempPath)
return tempPath, nil
}
@@ -166,23 +168,37 @@ func deterministicCachePath(transport, connID, remotePath string, fileSize int64
return filepath.Join(cacheTempDir, fileName), nil
}
// copyFile 复制文件内容
func copyFile(src, dst string) error {
in, err := os.Open(src)
if err != nil {
return err
// CleanupSiteCacheDirs 清理超过 24h 的站点预览缓存目录
// os.TempDir() 下两个前缀是旧版 MkdirTemp 随机目录残留(sftp 与 oss 各一种)
func CleanupSiteCacheDirs() {
cutoff := time.Now().Add(-downloadCacheTTL)
cleaned := cleanupExpiredDirs(cacheTempDir, "site-", cutoff)
cleaned += cleanupExpiredDirs(os.TempDir(), "udesk-site-", cutoff)
cleaned += cleanupExpiredDirs(os.TempDir(), "udesk-sftp-site-", cutoff)
if cleaned > 0 {
slog.Info("清理过期站点缓存目录", "count", cleaned)
}
defer in.Close()
}
out, err := os.Create(dst)
// cleanupExpiredDirs 删除 dir 下修改时间早于 cutoff 的 prefix 前缀子目录,返回清理数量
func cleanupExpiredDirs(dir, prefix string, cutoff time.Time) int {
entries, err := os.ReadDir(dir)
if err != nil {
return err
return 0
}
defer out.Close()
if _, err := out.ReadFrom(in); err != nil {
os.Remove(dst)
return err
cleaned := 0
for _, e := range entries {
if !e.IsDir() || !strings.HasPrefix(e.Name(), prefix) {
continue
}
info, err := e.Info()
if err != nil {
continue
}
if info.ModTime().Before(cutoff) {
os.RemoveAll(filepath.Join(dir, e.Name()))
cleaned++
}
}
return nil
return cleaned
}