calculate file checksum when updating file using wopi or text/code editor or webdav upload

update-checksum
Weidi Deng 1 year ago
parent a26893aabc
commit 192b698382

@ -1,9 +1,12 @@
package fsctx package fsctx
import ( import (
"encoding/hex"
"errors" "errors"
"github.com/HFO4/aliyun-oss-go-sdk/oss" "github.com/HFO4/aliyun-oss-go-sdk/oss"
"hash"
"io" "io"
"strings"
"time" "time"
) )
@ -121,3 +124,24 @@ func (file *FileStream) SetSize(size uint64) {
func (file *FileStream) SetModel(fileModel interface{}) { func (file *FileStream) SetModel(fileModel interface{}) {
file.Model = fileModel file.Model = fileModel
} }
type ChecksumFileStream struct {
Md5 hash.Hash
Sha1 hash.Hash
io.Reader
io.Closer
}
func (file *ChecksumFileStream) Hash() string {
var sb strings.Builder
sb.WriteString("MD5:")
sb.WriteString(hex.EncodeToString(file.Md5.Sum(nil)))
sb.WriteByte(' ')
sb.WriteString("SHA1:")
sb.WriteString(hex.EncodeToString(file.Sha1.Sum(nil)))
return sb.String()
}

@ -2,6 +2,8 @@ package filesystem
import ( import (
"context" "context"
"crypto/md5"
"crypto/sha1"
model "github.com/cloudreve/Cloudreve/v3/models" model "github.com/cloudreve/Cloudreve/v3/models"
"github.com/cloudreve/Cloudreve/v3/pkg/cache" "github.com/cloudreve/Cloudreve/v3/pkg/cache"
"github.com/cloudreve/Cloudreve/v3/pkg/cluster" "github.com/cloudreve/Cloudreve/v3/pkg/cluster"
@ -9,6 +11,7 @@ import (
"github.com/cloudreve/Cloudreve/v3/pkg/filesystem/fsctx" "github.com/cloudreve/Cloudreve/v3/pkg/filesystem/fsctx"
"github.com/cloudreve/Cloudreve/v3/pkg/serializer" "github.com/cloudreve/Cloudreve/v3/pkg/serializer"
"github.com/cloudreve/Cloudreve/v3/pkg/util" "github.com/cloudreve/Cloudreve/v3/pkg/util"
"io"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"strconv" "strconv"
@ -282,23 +285,29 @@ func NewWebdavAfterUploadHook(request *http.Request) func(ctx context.Context, f
modtime = time.Unix(timeUnix, 0) modtime = time.Unix(timeUnix, 0)
} }
} }
checksum := request.Header.Get("OC-Checksum")
return func(ctx context.Context, fs *FileSystem, newFile fsctx.FileHeader) error { return func(ctx context.Context, fs *FileSystem, newFile fsctx.FileHeader) error {
file := newFile.Info().Model.(*model.File) file := newFile.Info().Model.(*model.File)
if !modtime.IsZero() { if !modtime.IsZero() {
err := model.DB.Model(file).UpdateColumn("updated_at", modtime).Error return model.DB.Model(file).UpdateColumn("updated_at", modtime).Error
if err != nil {
return err
}
}
if checksum != "" {
return file.UpdateMetadata(map[string]string{
model.ChecksumMetadataKey: checksum,
})
} }
return nil return nil
} }
} }
// NewChecksumFileStreamAndAfterUploadHook 创建一个计算hash的数据流和相应的钩子函数
func NewChecksumFileStreamAndAfterUploadHook(rc io.ReadCloser) (io.ReadCloser, Hook) {
cfs := &fsctx.ChecksumFileStream{
Md5: md5.New(),
Sha1: sha1.New(),
Closer: rc,
}
cfs.Reader = io.TeeReader(rc, io.MultiWriter(cfs.Md5, cfs.Sha1))
return cfs, func(ctx context.Context, fs *FileSystem, newFile fsctx.FileHeader) error {
file := newFile.Info().Model.(*model.File)
return file.UpdateMetadata(map[string]string{
model.ChecksumMetadataKey: cfs.Hash(),
})
}
}

@ -344,9 +344,13 @@ func (h *Handler) handlePut(w http.ResponseWriter, r *http.Request, fs *filesyst
} }
fileName := path.Base(reqPath) fileName := path.Base(reqPath)
filePath := path.Dir(reqPath) filePath := path.Dir(reqPath)
// 计算hash
file, hook := filesystem.NewChecksumFileStreamAndAfterUploadHook(r.Body)
fileData := fsctx.FileStream{ fileData := fsctx.FileStream{
MimeType: r.Header.Get("Content-Type"), MimeType: r.Header.Get("Content-Type"),
File: r.Body, File: file,
Size: fileSize, Size: fileSize,
Name: fileName, Name: fileName,
VirtualPath: filePath, VirtualPath: filePath,
@ -391,6 +395,7 @@ func (h *Handler) handlePut(w http.ResponseWriter, r *http.Request, fs *filesyst
// rclone 请求 // rclone 请求
fs.Use("AfterUpload", filesystem.NewWebdavAfterUploadHook(r)) fs.Use("AfterUpload", filesystem.NewWebdavAfterUploadHook(r))
fs.Use("AfterUpload", hook)
// 执行上传 // 执行上传
err = fs.Upload(ctx, &fileData) err = fs.Upload(ctx, &fileData)

@ -411,9 +411,12 @@ func (service *FileIDService) PutContent(ctx context.Context, c *gin.Context) se
return serializer.ParamErr("Invalid content-length value", err) return serializer.ParamErr("Invalid content-length value", err)
} }
// 计算hash
file, hook := filesystem.NewChecksumFileStreamAndAfterUploadHook(c.Request.Body)
fileData := fsctx.FileStream{ fileData := fsctx.FileStream{
MimeType: c.Request.Header.Get("Content-Type"), MimeType: c.Request.Header.Get("Content-Type"),
File: c.Request.Body, File: file,
Size: fileSize, Size: fileSize,
Mode: fsctx.Overwrite, Mode: fsctx.Overwrite,
} }
@ -453,6 +456,7 @@ func (service *FileIDService) PutContent(ctx context.Context, c *gin.Context) se
fs.Use("BeforeUpload", filesystem.HookValidateFile) fs.Use("BeforeUpload", filesystem.HookValidateFile)
fs.Use("BeforeUpload", filesystem.HookValidateCapacityDiff) fs.Use("BeforeUpload", filesystem.HookValidateCapacityDiff)
fs.Use("AfterUpload", filesystem.GenericAfterUpdate) fs.Use("AfterUpload", filesystem.GenericAfterUpdate)
fs.Use("AfterUpload", hook)
// 执行上传 // 执行上传
uploadCtx = context.WithValue(uploadCtx, fsctx.FileModelCtx, originFile[0]) uploadCtx = context.WithValue(uploadCtx, fsctx.FileModelCtx, originFile[0])

Loading…
Cancel
Save