// Copyright 2022 ROC. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. package storage import ( "fmt" "io" "os" "path/filepath" "strings" "time" "github.com/Masterminds/semver/v3" "github.com/cockroachdb/errors" "github.com/rocboss/paopao-ce/internal/core" "github.com/sirupsen/logrus" ) var ( _ core.ObjectStorageService = (*localossServant)(nil) _ core.OssCreateService = (*localossCreateServant)(nil) _ core.OssCreateService = (*localossCreateTempDirServant)(nil) _ core.VersionInfo = (*localossServant)(nil) ) type localossCreateServant struct { savePath string domain string } type localossCreateTempDirServant struct { savePath string domain string tempDir string } type localossServant struct { core.OssCreateService savePath string domain string } func (s *localossCreateServant) PutObject(objectKey string, reader io.Reader, objectSize int64, contentType string, _persistance bool) (string, error) { saveDir := s.savePath + filepath.Dir(objectKey) err := os.MkdirAll(saveDir, 0750) if err != nil && !os.IsExist(err) { return "", err } savePath := s.savePath + objectKey writer, err := os.Create(savePath) if err != nil { return "", err } defer writer.Close() written, err := io.Copy(writer, reader) if err != nil { return "", err } if written != objectSize { os.Remove(savePath) return "", errors.New("put object not complete") } return s.domain + objectKey, nil } func (s *localossCreateServant) PersistObject(_objectKey string) error { // empty return nil } func (s *localossCreateTempDirServant) PutObject(objectKey string, reader io.Reader, objectSize int64, contentType string, persistance bool) (string, error) { objectName := objectKey if !persistance { objectName = s.tempDir + objectKey } saveDir := s.savePath + filepath.Dir(objectName) err := os.MkdirAll(saveDir, 0750) if err != nil && !os.IsExist(err) { return "", err } savePath := s.savePath + objectName writer, err := os.Create(savePath) if err != nil { return "", err } defer writer.Close() written, err := io.Copy(writer, reader) if err != nil { return "", err } if written != objectSize { os.Remove(savePath) return "", errors.New("put object not complete") } return s.domain + objectKey, nil } func (s *localossCreateTempDirServant) PersistObject(objectKey string) error { fi, err := os.Stat(s.savePath + objectKey) if err == nil && !fi.IsDir() { logrus.Debugf("object exist so do nothing objectKey: %s", objectKey) return nil } saveDir := s.savePath + filepath.Dir(objectKey) if err = os.MkdirAll(saveDir, 0750); err != nil && !os.IsExist(err) { return err } tmpObjPath := s.savePath + s.tempDir + objectKey reader, err := os.Open(tmpObjPath) if err != nil { return err } needCloseReader := true defer func() { if needCloseReader { reader.Close() } }() writer, err := os.Create(s.savePath + objectKey) if err != nil { return err } defer writer.Close() if _, err = io.Copy(writer, reader); err != nil { return err } reader.Close() needCloseReader = false if err = os.Remove(tmpObjPath); err != nil { return err } return nil } func (s *localossServant) DeleteObject(objectKey string) error { return os.Remove(s.savePath + objectKey) } func (s *localossServant) DeleteObjects(objectKeys []string) (err error) { // 宽松处理删除动作,尽可能删除所有objectKey,如果出错,只返回最后一个错误 for _, objectKey := range objectKeys { if e := os.Remove(s.savePath + objectKey); e != nil { err = e } } return } func (s *localossServant) IsObjectExist(objectKey string) (bool, error) { fi, err := os.Stat(s.savePath + objectKey) if err != nil { return false, err } return !fi.IsDir(), nil } func (s *localossServant) SignURL(objectKey string, expiredInSec int64) (string, error) { if expiredInSec < 0 { return "", fmt.Errorf("invalid expires: %d, expires must bigger than 0", expiredInSec) } expiration := time.Now().Unix() + expiredInSec // Fixed: Just make things simple and simple now so return an veiry simple sign url. // Maybe make another process logic for sign url in future but not now. uri := fmt.Sprintf("%s%s?expired=%d", s.domain, objectKey, expiration) return uri, nil } func (s *localossServant) ObjectURL(objetKey string) string { return s.domain + objetKey } func (s *localossServant) ObjectKey(objectUrl string) string { return strings.Replace(objectUrl, s.domain, "", -1) } func (s *localossServant) Name() string { return "LocalOSS" } func (s *localossServant) Version() *semver.Version { return semver.MustParse("v0.2.0") }