package rclone import ( "context" "crypto/sha256" "io" "time" "github.com/inhies/go-bytesize" "github.com/rclone/rclone/fs" "gitlink.org.cn/cloudream/common/pkgs/logger" "gitlink.org.cn/cloudream/common/utils/io2" stgtypes "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/storage/types" jcstypes "gitlink.org.cn/cloudream/jcs-pub/common/types" ) type BaseStore struct { Fs fs.Fs Detail *jcstypes.UserSpaceDetail } func NewBaseStore(fs fs.Fs, detail *jcstypes.UserSpaceDetail) *BaseStore { return &BaseStore{ Fs: fs, Detail: detail, } } func (s *BaseStore) Write(pat jcstypes.JPath, stream io.Reader, opt stgtypes.WriteOption) (stgtypes.FileInfo, error) { modTime := opt.ModTime if modTime.IsZero() { modTime = time.Now() } dir := pat.CopyParent() if dir.Len() > 0 { err := s.Fs.Mkdir(context.Background(), dir.String()) if err != nil { return stgtypes.FileInfo{}, err } } counter := io2.Counter(stream) hasher := io2.NewReadHasher(sha256.New(), counter) _, err := s.Fs.Put(context.Background(), hasher, &ObjectInfo{ RemoteValue: pat.String(), ModTimeValue: modTime, SizeValue: -1, }) if err != nil { return stgtypes.FileInfo{}, err } return stgtypes.FileInfo{ Path: pat, Size: counter.Count(), Hash: jcstypes.NewFullHash(hasher.Sum()), }, nil } func (s *BaseStore) Read(objPath jcstypes.JPath, opt stgtypes.OpenOption) (io.ReadCloser, error) { if opt.Length == 0 { return io2.ErrorReader(io.EOF), nil } var opts []fs.OpenOption if opt.Length > 0 { opts = append(opts, &fs.RangeOption{ Start: opt.Offset, End: opt.Offset + opt.Length - 1, }) } else if opt.Offset > 0 { opts = append(opts, &fs.SeekOption{ Offset: opt.Offset, }) } obj, err := s.Fs.NewObject(context.Background(), objPath.String()) if err != nil { return nil, err } return obj.Open(context.Background(), opts...) } func (s *BaseStore) Mkdir(path jcstypes.JPath) error { return s.Fs.Mkdir(context.Background(), path.String()) } func (s *BaseStore) ReadDir(pat jcstypes.JPath) stgtypes.DirReader { return NewDirReader(s.Fs, pat.String(), pat.Clone()) } func (s *BaseStore) CleanTemps() { log := s.getLogger() startTime := time.Now() tempDir := Join(s.Detail.UserSpace.WorkingDir.String(), stgtypes.TempWorkingDir) cnt, size := s.cleanTemps(tempDir, false) log.Infof("clean %d temp files, size: %v, time: %v", cnt, bytesize.ByteSize(size), time.Since(startTime)) } func (s *BaseStore) cleanTemps(root string, removeRoot bool) (int, int64) { log := s.getLogger() es, err := s.Fs.List(context.Background(), root) if err != nil { log.Warnf("list dir %v: %v", root, err) return 0, 0 } cnt := 0 size := int64(0) for _, e := range es { switch e := e.(type) { case fs.Object: err := e.Remove(context.Background()) if err != nil { log.Warnf("remove file %v: %v", e.Remote(), err) } else { cnt++ size += e.Size() } case fs.Directory: c, s := s.cleanTemps(e.Remote(), true) cnt += c size += s } } if removeRoot { err := s.Fs.Rmdir(context.Background(), root) if err != nil { log.Warnf("remove dir %v: %v", root, err) } } return cnt, size } func (s *BaseStore) Test() error { _, err := s.Fs.List(context.Background(), "") return err } func (s *BaseStore) getLogger() logger.Logger { return logger.WithField("BaseStore", "RClone").WithField("UserSpace", s.Detail.UserSpace) }