diff --git a/pkg/filesystem/fsctx/stream.go b/pkg/filesystem/fsctx/stream.go index 0f1fafd..0cba29e 100644 --- a/pkg/filesystem/fsctx/stream.go +++ b/pkg/filesystem/fsctx/stream.go @@ -19,7 +19,7 @@ const ( type FileStream struct { Mode WriteMode Hidden bool - LastModified time.Time + LastModified *time.Time Metadata map[string]string File io.ReadCloser Size uint64 @@ -61,7 +61,7 @@ func (file *FileStream) GetMetadata() map[string]string { return file.Metadata } -func (file *FileStream) GetLastModified() time.Time { +func (file *FileStream) GetLastModified() *time.Time { return file.LastModified } @@ -87,7 +87,7 @@ type FileHeader interface { GetVirtualPath() string GetMode() WriteMode GetMetadata() map[string]string - GetLastModified() time.Time + GetLastModified() *time.Time IsHidden() bool GetSavePath() string SetSize(uint64) diff --git a/pkg/filesystem/upload.go b/pkg/filesystem/upload.go index 3299819..e304651 100644 --- a/pkg/filesystem/upload.go +++ b/pkg/filesystem/upload.go @@ -149,7 +149,7 @@ func (fs *FileSystem) CancelUpload(ctx context.Context, path string, file fsctx. } // CreateUploadSession 创建上传会话 -func (fs *FileSystem) CreateUploadSession(ctx context.Context, path string, size uint64, name string) (*serializer.UploadCredential, error) { +func (fs *FileSystem) CreateUploadSession(ctx context.Context, file *fsctx.FileStream) (*serializer.UploadCredential, error) { // 获取相关有效期设置 credentialTTL := model.GetIntSetting("upload_credential_timeout", 3600) callBackSessionTTL := model.GetIntSetting("upload_session_timeout", 86400) @@ -157,16 +157,12 @@ func (fs *FileSystem) CreateUploadSession(ctx context.Context, path string, size callbackKey := uuid.Must(uuid.NewV4()).String() // 创建隐藏的文件,同时校验文件信息 - file := &fsctx.FileStream{ - Size: size, - Name: name, - VirtualPath: path, - Mode: fsctx.Nop, - Hidden: true, - Metadata: map[string]string{ - UploadSessionMetaKey: callbackKey, - }, + file.Mode = fsctx.Nop + file.Hidden = true + file.Metadata = map[string]string{ + UploadSessionMetaKey: callbackKey, } + fs.Use("BeforeUpload", HookValidateFile) fs.Use("AfterUpload", HookClearFileHeaderSize) fs.Use("AfterUpload", GenericAfterUpload) @@ -175,14 +171,15 @@ func (fs *FileSystem) CreateUploadSession(ctx context.Context, path string, size } uploadSession := &serializer.UploadSession{ - Key: callbackKey, - UID: fs.User.ID, - PolicyID: fs.Policy.ID, - VirtualPath: path, - Name: name, - Size: size, - SavePath: file.SavePath, - ChunkSize: fs.Policy.OptionsSerialized.ChunkSize, + Key: callbackKey, + UID: fs.User.ID, + PolicyID: fs.Policy.ID, + VirtualPath: file.VirtualPath, + Name: file.Name, + Size: file.Size, + SavePath: file.SavePath, + ChunkSize: fs.Policy.OptionsSerialized.ChunkSize, + LastModified: file.GetLastModified(), } // 获取上传凭证 diff --git a/pkg/serializer/upload.go b/pkg/serializer/upload.go index 2285410..87fd8e1 100644 --- a/pkg/serializer/upload.go +++ b/pkg/serializer/upload.go @@ -4,6 +4,7 @@ import ( "encoding/base64" "encoding/gob" "encoding/json" + "time" ) // UploadPolicy slave模式下传递的上传策略 @@ -31,14 +32,15 @@ type UploadCredential struct { // UploadSession 上传会话 type UploadSession struct { - Key string - UID uint - PolicyID uint - VirtualPath string - Name string - Size uint64 - SavePath string - ChunkSize uint64 + Key string // 上传会话 GUID + UID uint // 发起者 + PolicyID uint + VirtualPath string // 用户文件路径,不含文件名 + Name string // 文件名 + Size uint64 // 文件大小 + SavePath string // 物理存储路径,包含物理文件名 + ChunkSize uint64 // 分块大小,0 为部分快 + LastModified *time.Time // 可选的文件最后修改日期 } // UploadCallback 上传回调正文 diff --git a/routers/router.go b/routers/router.go index df46588..dd64545 100644 --- a/routers/router.go +++ b/routers/router.go @@ -504,8 +504,6 @@ func InitMasterRouter() *gin.Engine { // 文件 file := auth.Group("file", middleware.HashID(hashid.FileID)) { - // 文件上传 - file.POST("upload", controllers.FileUploadStream) // 创建上传会话 file.PUT("upload/session", controllers.GetUploadCredential) // 更新文件 diff --git a/service/explorer/upload.go b/service/explorer/upload.go index 04662b4..282a8cc 100644 --- a/service/explorer/upload.go +++ b/service/explorer/upload.go @@ -4,17 +4,20 @@ import ( "context" "github.com/cloudreve/Cloudreve/v3/pkg/filesystem" + "github.com/cloudreve/Cloudreve/v3/pkg/filesystem/fsctx" "github.com/cloudreve/Cloudreve/v3/pkg/hashid" "github.com/cloudreve/Cloudreve/v3/pkg/serializer" "github.com/gin-gonic/gin" + "time" ) // UploadSessionService 获取上传凭证服务 type UploadSessionService struct { - Path string `json:"path" binding:"required"` - Size uint64 `json:"size" binding:"min=0"` - Name string `json:"name" binding:"required"` - PolicyID string `json:"policy_id" binding:"required"` + Path string `json:"path" binding:"required"` + Size uint64 `json:"size" binding:"min=0"` + Name string `json:"name" binding:"required"` + PolicyID string `json:"policy_id" binding:"required"` + LastModified int64 `json:"last_modified"` } // Create 创建新的上传会话 @@ -35,7 +38,16 @@ func (service *UploadSessionService) Create(ctx context.Context, c *gin.Context) return serializer.Err(serializer.CodePolicyNotAllowed, "存储策略发生变化,请刷新文件列表并重新添加此任务", nil) } - credential, err := fs.CreateUploadSession(ctx, service.Path, service.Size, service.Name) + file := &fsctx.FileStream{ + Size: service.Size, + Name: service.Name, + VirtualPath: service.Path, + } + if service.LastModified > 0 { + lastModified := time.UnixMilli(service.LastModified) + file.LastModified = &lastModified + } + credential, err := fs.CreateUploadSession(ctx, file) if err != nil { return serializer.Err(serializer.CodeNotSet, err.Error(), err) }