if the file being received already exists locally, it will be renamed

This commit is contained in:
2026-02-07 19:39:14 +08:00
parent e76ada9b4b
commit e76bcd709c
13 changed files with 114 additions and 90 deletions

View File

@@ -8,11 +8,10 @@ import (
"path/filepath"
)
func (s *Service) SaveHistory() {
func (s *Service) SaveHistory(transfers []*Transfer) {
if !s.config.GetSaveHistory() {
return
}
transfers := s.GetTransferList()
configDir := config.GetConfigDir()
historyPath := filepath.Join(configDir, "history.json")
historyJson, err := json.Marshal(transfers)

View File

@@ -34,20 +34,21 @@ const (
// Transfer
type Transfer struct {
ID string `json:"id" binding:"required"` // 传输会话 ID
CreateTime int64 `json:"create_time"` // 创建时间
Sender discovery.Peer `json:"sender" binding:"required"` // 发送者
FileName string `json:"file_name"` // 文件名
FileSize int64 `json:"file_size"` // 文件大小 (字节)
SavePath string `json:"savePath"` // 保存路径
Status TransferStatus `json:"status"` // 传输状态
Progress Progress `json:"progress"` // 传输进度
Type TransferType `json:"type"` // 进度类型
ContentType ContentType `json:"content_type"` // 内容类型
Text string `json:"text"` // 文本内容
ErrorMsg string `json:"error_msg"` // 错误信息
Token string `json:"token"` // 用于上传的凭证
DecisionChan chan Decision `json:"-"` // 用户决策通道
ID string `json:"id" binding:"required"` // 传输会话 ID
CreateTime int64 `json:"create_time"` // 创建时间
Sender discovery.Peer `json:"sender" binding:"required"` // 发送者
// FileName 如果 ContentType 为 file文件名如果 ContentType 为 folder文件夹名如果 ContentType 为 text
FileName string `json:"file_name"` // 文件
FileSize int64 `json:"file_size"` // 文件大小 (字节)
SavePath string `json:"savePath"` // 保存路径
Status TransferStatus `json:"status"` // 传输状态
Progress Progress `json:"progress"` // 传输进度
Type TransferType `json:"type"` // 进度类型
ContentType ContentType `json:"content_type"` // 内容类型
Text string `json:"text"` // 文本内容
ErrorMsg string `json:"error_msg"` // 错误信息
Token string `json:"token"` // 用于上传的凭证
DecisionChan chan Decision `json:"-"` // 用户决策通道
}
type TransferOption func(*Transfer)

View File

@@ -175,6 +175,14 @@ func (s *Service) handleUpload(c *gin.Context) {
switch task.ContentType {
case ContentTypeFile:
destPath := filepath.Join(savePath, task.FileName)
// 如果文件已存在则在文件名后追加序号
_, err := os.Stat(destPath)
counter := 1
for err == nil {
destPath = filepath.Join(savePath, fmt.Sprintf("%s (%d)%s", strings.TrimSuffix(task.FileName, filepath.Ext(task.FileName)), counter, filepath.Ext(task.FileName)))
counter++
_, err = os.Stat(destPath)
}
file, err := os.Create(destPath)
if err != nil {
// 接收方无法创建文件,直接报错,任务结束
@@ -189,17 +197,17 @@ func (s *Service) handleUpload(c *gin.Context) {
return
}
defer file.Close()
s.receive(c, task, file, ctxReader)
s.receive(c, task, Writer{w: file, filePath: destPath}, ctxReader)
case ContentTypeText:
var buf bytes.Buffer
s.receive(c, task, &buf, ctxReader)
s.receive(c, task, Writer{w: &buf, filePath: ""}, ctxReader)
task.Text = buf.String()
case ContentTypeFolder:
s.receiveFolder(c, savePath, task, ctxReader)
}
}
func (s *Service) receive(c *gin.Context, task *Transfer, writer io.Writer, ctxReader io.Reader) {
func (s *Service) receive(c *gin.Context, task *Transfer, writer Writer, ctxReader io.Reader) {
// 包装 reader用于计算进度
reader := &PassThroughReader{
Reader: ctxReader,
@@ -248,6 +256,11 @@ func (s *Service) receive(c *gin.Context, task *Transfer, writer io.Writer, ctxR
slog.Error("Failed to write file", "error", err, "component", "transfer")
task.Status = TransferStatusError
task.ErrorMsg = fmt.Errorf("failed to write file: %v", err).Error()
// 删除文件
if task.ContentType == ContentTypeFile && writer.GetFilePath() != "" {
_ = os.Remove(writer.GetFilePath())
}
return
}
@@ -265,6 +278,14 @@ func (s *Service) receiveFolder(c *gin.Context, savePath string, task *Transfer,
// 创建根目录
destPath := filepath.Join(savePath, task.FileName)
// 如果文件已存在则在文件名后追加序号
_, err := os.Stat(destPath)
counter := 1
for err == nil {
destPath = filepath.Join(savePath, fmt.Sprintf("%s (%d)", task.FileName, counter))
counter++
_, err = os.Stat(destPath)
}
if err := os.MkdirAll(destPath, 0755); err != nil {
c.JSON(http.StatusInternalServerError, TransferUploadResponse{
ID: task.ID,

View File

@@ -128,13 +128,13 @@ func (s *Service) StoreTransfersToList(transfers []*Transfer) {
for _, transfer := range transfers {
s.transferList.Store(transfer.ID, transfer)
}
s.SaveHistory()
s.SaveHistory(transfers)
s.NotifyTransferListUpdate()
}
func (s *Service) StoreTransferToList(transfer *Transfer) {
s.transferList.Store(transfer.ID, transfer)
s.SaveHistory()
s.SaveHistory([]*Transfer{transfer})
s.NotifyTransferListUpdate()
}
@@ -154,12 +154,12 @@ func (s *Service) CleanFinishedTransferList() {
}
return true
})
s.SaveHistory()
s.SaveHistory(s.GetTransferList())
s.NotifyTransferListUpdate()
}
func (s *Service) DeleteTransfer(transferID string) {
s.transferList.Delete(transferID)
s.SaveHistory()
s.SaveHistory(s.GetTransferList())
s.NotifyTransferListUpdate()
}

View File

@@ -0,0 +1,16 @@
package transfer
import "io"
type Writer struct {
w io.Writer
filePath string
}
func (w Writer) Write(p []byte) (n int, err error) {
return w.w.Write(p)
}
func (w Writer) GetFilePath() string {
return w.filePath
}