fix(drivers/189pc): preserve file extension during family transfer (#3083)

* fix(189pc): preserve family transfer extension

- Preserve the source extension in family-transfer temporary upload names.
- Fall back to .transfer for extensionless source files.
- Add unit coverage for extension handling.

Co-authored-by: Codex <267193182+codex@users.noreply.github.com>

* fix(189pc): include extension in upload progress key

- Separate resumable upload state for identical content with different extensions.
- Preserve resume behavior when only the temporary file name changes.
- Add unit coverage for both cases.

Co-authored-by: Codex <267193182+codex@users.noreply.github.com>

---------

Co-authored-by: Codex <267193182+codex@users.noreply.github.com>
This commit is contained in:
qcnhy
2026-10-10 11:00:58 +08:00
committed by GitHub
parent 4c39bbe9c2
commit 61e535c965
3 changed files with 63 additions and 3 deletions
+10 -1
View File
@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"net/http"
"path"
"strconv"
"strings"
"time"
@@ -366,6 +367,14 @@ func (y *Cloud189PC) Remove(ctx context.Context, obj model.Obj) error {
return y.WaitBatchTask("DELETE", resp.TaskID, time.Millisecond*200)
}
func familyTransferTempName(srcName string) string {
ext := path.Ext(srcName)
if ext == "" {
ext = ".transfer"
}
return fmt.Sprintf("0%s%s", uuid.NewString(), ext)
}
func (y *Cloud189PC) Put(ctx context.Context, dstDir model.Obj, stream model.FileStreamer, up driver.UpdateProgress) (newObj model.Obj, err error) {
overwrite := true
isFamily := y.isFamily()
@@ -399,7 +408,7 @@ func (y *Cloud189PC) Put(ctx context.Context, dstDir model.Obj, stream model.Fil
srcName := stream.GetName()
stream = &WrapFileStreamer{
FileStreamer: stream,
Name: fmt.Sprintf("0%s.transfer", uuid.NewString()),
Name: familyTransferTempName(srcName),
}
// 使用家庭云上传
+45
View File
@@ -0,0 +1,45 @@
package _189pc
import (
"path"
"slices"
"strings"
"testing"
)
func TestFamilyTransferTempNamePreservesExtension(t *testing.T) {
tests := []struct {
name string
want string
}{
{name: "photo.jpg", want: ".jpg"},
{name: "PHOTO.PNG", want: ".PNG"},
{name: "archive.tar.gz", want: ".gz"},
{name: "no-extension", want: ".transfer"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := familyTransferTempName(tt.name)
if !strings.HasPrefix(got, "0") {
t.Fatalf("temporary name %q must start with 0", got)
}
if ext := path.Ext(got); ext != tt.want {
t.Fatalf("temporary name extension = %q, want %q", ext, tt.want)
}
})
}
}
func TestUploadProgressKeysIncludeExtension(t *testing.T) {
jpgKeys := uploadProgressKeys("session", "same-md5", "photo.jpg")
txtKeys := uploadProgressKeys("session", "same-md5", "photo.txt")
retryKeys := uploadProgressKeys("session", "same-md5", "different-name.jpg")
if slices.Equal(jpgKeys, txtKeys) {
t.Fatal("files with different extensions must not share upload progress")
}
if !slices.Equal(jpgKeys, retryKeys) {
t.Fatal("files with the same session, MD5, and extension should share upload progress")
}
}
+8 -2
View File
@@ -14,6 +14,7 @@ import (
"net/http/cookiejar"
"net/url"
"os"
"path"
"regexp"
"sort"
"strconv"
@@ -1203,6 +1204,10 @@ func (y *Cloud189PC) FastUpload(ctx context.Context, dstDir model.Obj, file mode
return y.fastUpload(ctx, dstDir, file, up, isFamily, overwrite, generateTorrent)
}
func uploadProgressKeys(sessionKey, fileMD5, fileName string) []string {
return []string{sessionKey, fileMD5, path.Ext(fileName)}
}
func (y *Cloud189PC) fastUpload(ctx context.Context, dstDir model.Obj, file model.FileStreamer, up driver.UpdateProgress, isFamily bool, overwrite bool, generateTorrent bool) (model.Obj, error) {
var (
cache = file.GetFile()
@@ -1305,7 +1310,8 @@ func (y *Cloud189PC) fastUpload(ctx context.Context, dstDir model.Obj, file mode
}
// 尝试恢复进度
uploadProgress, ok := base.GetUploadProgress[*UploadProgress](y, y.getTokenInfo().SessionKey, fileMd5Hex)
progressKeys := uploadProgressKeys(y.getTokenInfo().SessionKey, fileMd5Hex, file.GetName())
uploadProgress, ok := base.GetUploadProgress[*UploadProgress](y, progressKeys...)
if !ok {
// step.2 预上传
params := Params{
@@ -1373,7 +1379,7 @@ func (y *Cloud189PC) fastUpload(ctx context.Context, dstDir model.Obj, file mode
if err = threadG.Wait(); err != nil {
if errors.Is(err, context.Canceled) {
uploadProgress.UploadParts = utils.SliceFilter(uploadProgress.UploadParts, func(s string) bool { return s != "" })
base.SaveUploadProgress(y, uploadProgress, y.getTokenInfo().SessionKey, fileMd5Hex)
base.SaveUploadProgress(y, uploadProgress, progressKeys...)
}
return nil, err
}