Feat: API for receiviing chunk data
This commit is contained in:
parent
72173bf894
commit
c301bd6045
8 changed files with 89 additions and 86 deletions
|
@ -218,5 +218,6 @@ func (handler Driver) Source(
|
|||
func (handler Driver) Token(ctx context.Context, ttl int64, uploadSession *serializer.UploadSession, file fsctx.FileHeader) (serializer.UploadCredential, error) {
|
||||
return serializer.UploadCredential{
|
||||
SessionID: uploadSession.Key,
|
||||
ChunkSize: handler.Policy.OptionsSerialized.ChunkSize,
|
||||
}, nil
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"os"
|
||||
"path"
|
||||
"time"
|
||||
|
||||
model "github.com/cloudreve/Cloudreve/v3/models"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/cache"
|
||||
|
@ -167,6 +168,7 @@ func (fs *FileSystem) CreateUploadSession(ctx context.Context, file *fsctx.FileS
|
|||
|
||||
fs.Use("BeforeUpload", HookValidateFile)
|
||||
fs.Use("AfterUpload", HookClearFileHeaderSize)
|
||||
// TODO: 只有本机策略才添加文件
|
||||
fs.Use("AfterUpload", GenericAfterUpload)
|
||||
if err := fs.Upload(ctx, file); err != nil {
|
||||
return nil, err
|
||||
|
@ -200,6 +202,9 @@ func (fs *FileSystem) CreateUploadSession(ctx context.Context, file *fsctx.FileS
|
|||
return nil, err
|
||||
}
|
||||
|
||||
// 补全上传凭证其他信息
|
||||
credential.Expires = time.Now().Add(time.Duration(callBackSessionTTL) * time.Second).Unix()
|
||||
|
||||
return &credential, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -46,12 +46,11 @@ type Object struct {
|
|||
|
||||
// PolicySummary 用于前端组件使用的存储策略概况
|
||||
type PolicySummary struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
MaxSize uint64 `json:"max_size"`
|
||||
FileType []string `json:"file_type"`
|
||||
ChunkSize uint64 `json:"chunk_size"`
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
MaxSize uint64 `json:"max_size"`
|
||||
FileType []string `json:"file_type"`
|
||||
}
|
||||
|
||||
// BuildObjectList 构建列目录响应
|
||||
|
@ -66,12 +65,11 @@ func BuildObjectList(parent uint, objects []Object, policy *model.Policy) Object
|
|||
|
||||
if policy != nil {
|
||||
res.Policy = &PolicySummary{
|
||||
ID: hashid.HashID(policy.ID, hashid.PolicyID),
|
||||
Name: policy.Name,
|
||||
Type: policy.Type,
|
||||
MaxSize: policy.MaxSize,
|
||||
FileType: policy.OptionsSerialized.FileType,
|
||||
ChunkSize: policy.OptionsSerialized.ChunkSize,
|
||||
ID: hashid.HashID(policy.ID, hashid.PolicyID),
|
||||
Name: policy.Name,
|
||||
Type: policy.Type,
|
||||
MaxSize: policy.MaxSize,
|
||||
FileType: policy.OptionsSerialized.FileType,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,8 @@ type UploadPolicy struct {
|
|||
// UploadCredential 返回给客户端的上传凭证
|
||||
type UploadCredential struct {
|
||||
SessionID string `json:"sessionID"`
|
||||
ChunkSize uint64 `json:"chunkSize"` // 分块大小,0 为部分快
|
||||
Expires int64 `json:"expires"` // 上传凭证过期时间, Unix 时间戳
|
||||
|
||||
Token string `json:"token"`
|
||||
Policy string `json:"policy"`
|
||||
|
@ -39,7 +41,7 @@ type UploadSession struct {
|
|||
Name string // 文件名
|
||||
Size uint64 // 文件大小
|
||||
SavePath string // 物理存储路径,包含物理文件名
|
||||
ChunkSize uint64 // 分块大小,0 为部分快
|
||||
ChunkSize uint64 // 分块大小,0 为不分快
|
||||
LastModified *time.Time // 可选的文件最后修改日期
|
||||
}
|
||||
|
||||
|
|
|
@ -31,14 +31,6 @@ type User struct {
|
|||
Tags []tag `json:"tags"`
|
||||
}
|
||||
|
||||
type policy struct {
|
||||
SaveType string `json:"saveType"`
|
||||
MaxSize string `json:"maxSize"`
|
||||
AllowedType []string `json:"allowedType"`
|
||||
UploadURL string `json:"upUrl"`
|
||||
AllowGetSource bool `json:"allowSource"`
|
||||
}
|
||||
|
||||
type group struct {
|
||||
ID uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
|
|
|
@ -3,15 +3,10 @@ package controllers
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/request"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/conf"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/filesystem"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/filesystem/fsctx"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/serializer"
|
||||
"github.com/cloudreve/Cloudreve/v3/service/explorer"
|
||||
"github.com/gin-gonic/gin"
|
||||
|
@ -285,72 +280,65 @@ func PutContent(c *gin.Context) {
|
|||
}
|
||||
}
|
||||
|
||||
// FileUploadStream 本地策略流式上传
|
||||
func FileUploadStream(c *gin.Context) {
|
||||
// FileUpload 本地策略文件上传
|
||||
func FileUpload(c *gin.Context) {
|
||||
// 创建上下文
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
// 取得文件大小
|
||||
fileSize, err := strconv.ParseUint(c.Request.Header.Get("Content-Length"), 10, 64)
|
||||
if err != nil {
|
||||
var service explorer.UploadService
|
||||
if err := c.ShouldBindUri(&service); err == nil {
|
||||
res := service.Upload(ctx, c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
return
|
||||
}
|
||||
|
||||
// 解码文件名和路径
|
||||
fileName, err := url.QueryUnescape(c.Request.Header.Get("X-Cr-FileName"))
|
||||
filePath, err := url.QueryUnescape(c.Request.Header.Get("X-Cr-Path"))
|
||||
if err != nil {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
return
|
||||
}
|
||||
|
||||
fileData := fsctx.FileStream{
|
||||
MIMEType: c.Request.Header.Get("Content-Type"),
|
||||
File: c.Request.Body,
|
||||
Size: fileSize,
|
||||
Name: fileName,
|
||||
VirtualPath: filePath,
|
||||
Mode: fsctx.Create,
|
||||
}
|
||||
|
||||
// 创建文件系统
|
||||
fs, err := filesystem.NewFileSystemFromContext(c)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(serializer.CodePolicyNotAllowed, err.Error(), err))
|
||||
return
|
||||
}
|
||||
|
||||
// 非可用策略时拒绝上传
|
||||
if !fs.Policy.IsTransitUpload(fileSize) {
|
||||
request.BlackHole(c.Request.Body)
|
||||
c.JSON(200, serializer.Err(serializer.CodePolicyNotAllowed, "当前存储策略无法使用", nil))
|
||||
return
|
||||
}
|
||||
|
||||
// 给文件系统分配钩子
|
||||
fs.Use("BeforeUpload", filesystem.HookValidateFile)
|
||||
fs.Use("BeforeUpload", filesystem.HookValidateCapacity)
|
||||
fs.Use("AfterUploadCanceled", filesystem.HookDeleteTempFile)
|
||||
fs.Use("AfterUploadCanceled", filesystem.HookGiveBackCapacity)
|
||||
fs.Use("AfterUpload", filesystem.GenericAfterUpload)
|
||||
fs.Use("AfterValidateFailed", filesystem.HookDeleteTempFile)
|
||||
fs.Use("AfterValidateFailed", filesystem.HookGiveBackCapacity)
|
||||
fs.Use("AfterUploadFailed", filesystem.HookGiveBackCapacity)
|
||||
|
||||
// 执行上传
|
||||
ctx = context.WithValue(ctx, fsctx.ValidateCapacityOnceCtx, &sync.Once{})
|
||||
uploadCtx := context.WithValue(ctx, fsctx.GinCtx, c)
|
||||
err = fs.Upload(uploadCtx, &fileData)
|
||||
if err != nil {
|
||||
c.JSON(200, serializer.Err(serializer.CodeUploadFailed, err.Error(), err))
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, serializer.Response{
|
||||
Code: 0,
|
||||
})
|
||||
//fileData := fsctx.FileStream{
|
||||
// MIMEType: c.Request.Header.Get("Content-Type"),
|
||||
// File: c.Request.Body,
|
||||
// Size: fileSize,
|
||||
// Name: fileName,
|
||||
// VirtualPath: filePath,
|
||||
// Mode: fsctx.Create,
|
||||
//}
|
||||
//
|
||||
//// 创建文件系统
|
||||
//fs, err := filesystem.NewFileSystemFromContext(c)
|
||||
//if err != nil {
|
||||
// c.JSON(200, serializer.Err(serializer.CodePolicyNotAllowed, err.Error(), err))
|
||||
// return
|
||||
//}
|
||||
//
|
||||
//// 非可用策略时拒绝上传
|
||||
//if !fs.Policy.IsTransitUpload(fileSize) {
|
||||
// request.BlackHole(c.Request.Body)
|
||||
// c.JSON(200, serializer.Err(serializer.CodePolicyNotAllowed, "当前存储策略无法使用", nil))
|
||||
// return
|
||||
//}
|
||||
//
|
||||
//// 给文件系统分配钩子
|
||||
//fs.Use("BeforeUpload", filesystem.HookValidateFile)
|
||||
//fs.Use("BeforeUpload", filesystem.HookValidateCapacity)
|
||||
//fs.Use("AfterUploadCanceled", filesystem.HookDeleteTempFile)
|
||||
//fs.Use("AfterUploadCanceled", filesystem.HookGiveBackCapacity)
|
||||
//fs.Use("AfterUpload", filesystem.GenericAfterUpload)
|
||||
//fs.Use("AfterValidateFailed", filesystem.HookDeleteTempFile)
|
||||
//fs.Use("AfterValidateFailed", filesystem.HookGiveBackCapacity)
|
||||
//fs.Use("AfterUploadFailed", filesystem.HookGiveBackCapacity)
|
||||
//
|
||||
//// 执行上传
|
||||
//ctx = context.WithValue(ctx, fsctx.ValidateCapacityOnceCtx, &sync.Once{})
|
||||
//uploadCtx := context.WithValue(ctx, fsctx.GinCtx, c)
|
||||
//err = fs.Upload(uploadCtx, &fileData)
|
||||
//if err != nil {
|
||||
// c.JSON(200, serializer.Err(serializer.CodeUploadFailed, err.Error(), err))
|
||||
// return
|
||||
//}
|
||||
//
|
||||
//c.JSON(200, serializer.Response{
|
||||
// Code: 0,
|
||||
//})
|
||||
}
|
||||
|
||||
// GetUploadCredential 创建上传会话
|
||||
|
|
|
@ -504,8 +504,10 @@ func InitMasterRouter() *gin.Engine {
|
|||
// 文件
|
||||
file := auth.Group("file", middleware.HashID(hashid.FileID))
|
||||
{
|
||||
// 文件上传
|
||||
file.POST("upload/:sessionId/:index", controllers.FileUpload)
|
||||
// 创建上传会话
|
||||
file.PUT("upload/session", controllers.GetUploadCredential)
|
||||
file.PUT("upload", controllers.GetUploadCredential)
|
||||
// 更新文件
|
||||
file.PUT("update/:id", controllers.PutContent)
|
||||
// 创建空白文件
|
||||
|
|
|
@ -2,6 +2,7 @@ package explorer
|
|||
|
||||
import (
|
||||
"context"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/request"
|
||||
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/filesystem"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/filesystem/fsctx"
|
||||
|
@ -57,3 +58,17 @@ func (service *UploadSessionService) Create(ctx context.Context, c *gin.Context)
|
|||
Data: credential,
|
||||
}
|
||||
}
|
||||
|
||||
// UploadService 本机策略上传服务
|
||||
type UploadService struct {
|
||||
ID string `uri:"sessionId" binding:"required"`
|
||||
Index int `uri:"index"`
|
||||
}
|
||||
|
||||
// Upload 处理本机文件分片上传
|
||||
func (service *UploadService) Upload(ctx context.Context, c *gin.Context) serializer.Response {
|
||||
request.BlackHole(c.Request.Body)
|
||||
return serializer.Response{
|
||||
Code: 0,
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue