|
- package local
-
- import (
- "context"
- "crypto/sha256"
- "fmt"
- "hash"
- "io"
- "os"
- "path/filepath"
-
- "gitlink.org.cn/cloudream/common/utils/io2"
- "gitlink.org.cn/cloudream/common/utils/os2"
- "gitlink.org.cn/cloudream/common/utils/sort2"
- stgtypes "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/storage/types"
- jcstypes "gitlink.org.cn/cloudream/jcs-pub/common/types"
- )
-
- type Multiparter struct {
- detail *jcstypes.UserSpaceDetail
- localStg *jcstypes.LocalCred
- feat *jcstypes.MultipartUploadFeature
- }
-
- func (*Multiparter) MinPartSize() int64 {
- return 1 * 1024 * 1024 // 1MB
- }
-
- func (*Multiparter) MaxPartSize() int64 {
- return 5 * 1024 * 1024 * 1024 // 5GB
- }
-
- func (m *Multiparter) Initiate(ctx context.Context) (stgtypes.MultipartTask, error) {
- tempDir := filepath.Join(m.localStg.RootDir, m.detail.UserSpace.WorkingDir.JoinOSPath(), stgtypes.TempWorkingDir)
- absTempDir, err := filepath.Abs(tempDir)
- if err != nil {
- return nil, fmt.Errorf("get abs temp dir %v: %v", tempDir, err)
- }
-
- tempFileName := os2.GenerateRandomFileName(10)
- tempPartsDir := filepath.Join(absTempDir, tempFileName)
- absJoinedFilePath := filepath.Join(absTempDir, tempFileName+".joined")
-
- err = os.MkdirAll(tempPartsDir, 0777)
-
- if err != nil {
- return nil, err
- }
-
- return &MultipartTask{
- absTempDir: absTempDir,
- tempFileName: tempFileName,
- tempPartsDir: tempPartsDir,
- joinedFileJPath: m.detail.UserSpace.WorkingDir.ConcatCompsNew(stgtypes.TempWorkingDir, tempFileName+".joined"),
- absJoinedFilePath: absJoinedFilePath,
- uploadID: tempPartsDir,
- }, nil
- }
-
- func (m *Multiparter) UploadPart(ctx context.Context, init stgtypes.MultipartInitState, partSize int64, partNumber int, stream io.Reader) (stgtypes.UploadedPartInfo, error) {
- partFilePath := filepath.Join(init.UploadID, fmt.Sprintf("%v", partNumber))
- partFile, err := os.Create(partFilePath)
- if err != nil {
- return stgtypes.UploadedPartInfo{}, err
- }
- defer partFile.Close()
-
- _, err = io.Copy(partFile, stream)
- if err != nil {
- return stgtypes.UploadedPartInfo{}, err
- }
- return stgtypes.UploadedPartInfo{
- ETag: partFilePath,
- PartNumber: partNumber,
- }, nil
- }
-
- type MultipartTask struct {
- absTempDir string // 应该要是绝对路径
- tempFileName string
- tempPartsDir string
- joinedFileJPath jcstypes.JPath
- absJoinedFilePath string
- uploadID string
- }
-
- func (i *MultipartTask) InitState() stgtypes.MultipartInitState {
- return stgtypes.MultipartInitState{
- UploadID: i.uploadID,
- }
- }
-
- func (i *MultipartTask) JoinParts(ctx context.Context, parts []stgtypes.UploadedPartInfo) (stgtypes.FileInfo, error) {
- parts = sort2.Sort(parts, func(l, r stgtypes.UploadedPartInfo) int {
- return l.PartNumber - r.PartNumber
- })
-
- joined, err := os.Create(i.absJoinedFilePath)
- if err != nil {
- return stgtypes.FileInfo{}, err
- }
- defer joined.Close()
-
- size := int64(0)
- hasher := sha256.New()
-
- for _, part := range parts {
- partSize, err := i.writePart(part, joined, hasher)
- if err != nil {
- return stgtypes.FileInfo{}, err
- }
-
- size += partSize
- }
-
- h := hasher.Sum(nil)
- return stgtypes.FileInfo{
- Path: i.joinedFileJPath,
- Size: size,
- Hash: jcstypes.NewFullHash(h),
- }, nil
- }
-
- func (i *MultipartTask) writePart(partInfo stgtypes.UploadedPartInfo, joined *os.File, hasher hash.Hash) (int64, error) {
- part, err := os.Open(partInfo.ETag)
- if err != nil {
- return 0, err
- }
- defer part.Close()
-
- buf := make([]byte, 32*1024)
- size := int64(0)
- for {
- n, err := part.Read(buf)
- if n > 0 {
- size += int64(n)
- io2.WriteAll(hasher, buf[:n])
- err := io2.WriteAll(joined, buf[:n])
- if err != nil {
- return 0, err
- }
- }
- if err == io.EOF {
- break
- }
- if err != nil {
- return 0, err
- }
- }
-
- return size, nil
- }
-
- func (i *MultipartTask) Close() {
- os.RemoveAll(i.tempPartsDir)
- }
|