修复: SFTP连接首拉不显示与传输挂起
- watcher握手期伪触发致幻影本地列表,根因修复 - 连接探测2.5s超时竞速,握手10s预算 - 30s保活自动掐死半开连接,取连接时剔除已断开 - 副本命名与进度计数抽公共,下载缓存清理去重
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -61,6 +61,8 @@ func InitFast() (*gorm.DB, error) {
|
||||
db.Exec("UPDATE connection_profiles SET provider = type, type = 'oss' WHERE type IN ('qiniu', 'aliyun')")
|
||||
// 为旧 BGM 播放列表补充 profile_id(找第一个 OSS profile)
|
||||
db.Exec("UPDATE bgm_playlist SET profile_id = (SELECT CAST(id AS VARCHAR) FROM connection_profiles WHERE type = 'oss' LIMIT 1) WHERE (profile_id = '' OR profile_id IS NULL) AND path NOT LIKE '%:'")
|
||||
// 清理历史版本 id 断链重复 INSERT 堆积的重复服务器配置,保留每组 id 最小的一行
|
||||
db.Exec("DELETE FROM connection_profiles WHERE id NOT IN (SELECT MIN(id) FROM connection_profiles GROUP BY name, type, host, port, bucket)")
|
||||
globalDB = db
|
||||
})
|
||||
if initErr != nil {
|
||||
|
||||
Reference in New Issue
Block a user