修复: 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
+12 -20
View File
@@ -11,6 +11,7 @@ import (
"io"
"net/http"
"net/url"
"sort"
"strings"
"time"
@@ -122,14 +123,7 @@ func (c *Client) canonicalizeOSSHeaders(headers map[string]string) string {
}
// 按字典序排序
// 这里简单处理,实际应该用排序算法
for i := 0; i < len(ossHeaders); i++ {
for j := i + 1; j < len(ossHeaders); j++ {
if ossHeaders[i] > ossHeaders[j] {
ossHeaders[i], ossHeaders[j] = ossHeaders[j], ossHeaders[i]
}
}
}
sort.Strings(ossHeaders)
// 拼接结果
if len(ossHeaders) == 0 {
@@ -315,13 +309,14 @@ func (c *Client) GetFileInfo(ctx context.Context, key string) (*oss.FileInfo, er
size := resp.ContentLength
etag := resp.Header.Get("ETag")
contentType := resp.Header.Get("Content-Type")
_ = resp.Header.Get("Last-Modified") // 预留,可能需要解析时间
lastModified, _ := http.ParseTime(resp.Header.Get("Last-Modified"))
return &oss.FileInfo{
Key: key,
Size: size,
ETag: strings.Trim(etag, "\""),
ContentType: contentType,
Key: key,
Size: size,
ETag: strings.Trim(etag, "\""),
ContentType: contentType,
LastModified: lastModified,
}, nil
}
@@ -487,26 +482,23 @@ func (c *Client) DeleteMultiple(ctx context.Context, keys []string) (*oss.Delete
// GetSignedURL 获取预签名URL
func (c *Client) GetSignedURL(ctx context.Context, key string, expiresIn time.Duration) (string, error) {
// 阿里云 OSS 使用签名 URL
// 格式: ?OSSAccessKeyId=xxx&Expires=xxx&Signature=xxx
expiration := time.Now().Add(expiresIn).Unix()
// 构建签名
// 签名计算用原始 key(不编码)
path := "/" + c.config.Bucket + "/" + key
stringToSign := "GET\n\n\n" + fmt.Sprintf("%d", expiration) + "\n" + path
h := hmac.New(sha1.New, []byte(c.config.AccessKeySecret))
h.Write([]byte(stringToSign))
signature := base64.StdEncoding.EncodeToString(h.Sum(nil))
signature = strings.TrimRight(signature, "=") // URL Safe
signature := base64.URLEncoding.EncodeToString(h.Sum(nil))
scheme := "https://"
if !c.config.UseHTTPS {
scheme = "http://"
}
baseURL := scheme + c.config.Bucket + "." + c.config.Endpoint + "/" + key
baseURL := scheme + c.config.Bucket + "." + c.config.Endpoint + "/" + url.PathEscape(key)
signedURL := fmt.Sprintf("%s?OSSAccessKeyId=%s&Expires=%d&Signature=%s",
baseURL, c.config.AccessKeyID, expiration, signature)
baseURL, url.QueryEscape(c.config.AccessKeyID), expiration, url.QueryEscape(signature))
return signedURL, nil
}