mirror of
https://github.com/samuelncui/yatm.git
synced 2026-01-03 11:45:21 +00:00
feat: add more manage features
This commit is contained in:
@@ -7,10 +7,12 @@ import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"path"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
mapset "github.com/deckarep/golang-set/v2"
|
||||
"github.com/samber/lo"
|
||||
"github.com/sirupsen/logrus"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
@@ -340,6 +342,30 @@ func (l *Library) List(ctx context.Context, parentID int64) ([]*File, error) {
|
||||
return l.list(ctx, l.db.WithContext(ctx), parentID)
|
||||
}
|
||||
|
||||
func (l *Library) ListWithSize(ctx context.Context, parentID int64) ([]*File, error) {
|
||||
all, err := l.listAll(ctx, l.db.WithContext(ctx), parentID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mapping := lo.GroupBy(all, func(file *File) int64 { return file.ParentID })
|
||||
var fetchSize func(file *File)
|
||||
fetchSize = func(file *File) {
|
||||
for _, child := range mapping[file.ID] {
|
||||
fetchSize(child)
|
||||
file.Size += child.Size
|
||||
}
|
||||
}
|
||||
|
||||
files := mapping[parentID]
|
||||
for _, f := range files {
|
||||
fetchSize(f)
|
||||
}
|
||||
|
||||
sort.Slice(files, func(i, j int) bool { return files[i].Name < files[j].Name })
|
||||
return files, nil
|
||||
}
|
||||
|
||||
func (l *Library) list(ctx context.Context, tx *gorm.DB, parentID int64) ([]*File, error) {
|
||||
files := make([]*File, 0, 4)
|
||||
if r := tx.Where("parent_id = ?", parentID).Order("name").Find(&files); r.Error != nil {
|
||||
@@ -348,6 +374,38 @@ func (l *Library) list(ctx context.Context, tx *gorm.DB, parentID int64) ([]*Fil
|
||||
return files, nil
|
||||
}
|
||||
|
||||
func (l *Library) listAll(ctx context.Context, tx *gorm.DB, parentIDs ...int64) ([]*File, error) {
|
||||
files := make([]*File, 0, 4)
|
||||
|
||||
current := parentIDs
|
||||
for {
|
||||
batch := make([]*File, 0, 4)
|
||||
if r := tx.Where("parent_id IN (?)", current).Find(&batch); r.Error != nil {
|
||||
return nil, fmt.Errorf("find files fail, %w", r.Error)
|
||||
}
|
||||
|
||||
if len(batch) == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
files = append(files, batch...)
|
||||
next := make([]int64, 0, 4)
|
||||
for _, f := range batch {
|
||||
if !fs.FileMode(f.Mode).IsDir() {
|
||||
continue
|
||||
}
|
||||
next = append(next, f.ID)
|
||||
}
|
||||
|
||||
if len(next) == 0 {
|
||||
break
|
||||
}
|
||||
current = next
|
||||
}
|
||||
|
||||
return files, nil
|
||||
}
|
||||
|
||||
func (l *Library) ListParents(ctx context.Context, id int64) ([]*File, error) {
|
||||
return l.listParnets(ctx, l.db.WithContext(ctx), id)
|
||||
}
|
||||
|
||||
@@ -4,6 +4,9 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
mapset "github.com/deckarep/golang-set/v2"
|
||||
"github.com/modern-go/reflect2"
|
||||
@@ -157,26 +160,56 @@ func (l *Library) Trim(ctx context.Context, position, file bool) error {
|
||||
}
|
||||
current = files[len(files)-1].ID
|
||||
|
||||
fileIDs := lo.Map(files, func(f *File, _ int) int64 { return f.ID })
|
||||
fileIDs := lo.Map(
|
||||
lo.Filter(files, func(f *File, _ int) bool { return fs.FileMode(f.Mode).IsRegular() }),
|
||||
func(f *File, _ int) int64 { return f.ID },
|
||||
)
|
||||
positions, err := l.MGetPositionByFileID(ctx, fileIDs...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("mget position by file id fail, %w", err)
|
||||
}
|
||||
|
||||
needDelete := make([]int64, 0)
|
||||
for _, file := range files {
|
||||
if posis, has := positions[file.ID]; has && len(posis) > 0 {
|
||||
needDeleteFileIDs := make([]int64, 0)
|
||||
needDeletePositionIDs := make([]int64, 0)
|
||||
for _, fileID := range fileIDs {
|
||||
posis, has := positions[fileID]
|
||||
if !has || len(posis) == 0 {
|
||||
needDeleteFileIDs = append(needDeleteFileIDs, fileID)
|
||||
continue
|
||||
}
|
||||
|
||||
needDelete = append(needDelete, file.ID)
|
||||
}
|
||||
if len(needDelete) == 0 {
|
||||
continue
|
||||
}
|
||||
if len(posis) == 1 {
|
||||
continue
|
||||
}
|
||||
|
||||
if r := l.db.WithContext(ctx).Where("id IN (?)", needDelete).Delete(ModelFile); r.Error != nil {
|
||||
return fmt.Errorf("delete files fail, err= %w", r.Error)
|
||||
sort.Slice(posis, func(i int, j int) bool {
|
||||
ii, jj := posis[i], posis[j]
|
||||
if ii.TapeID != jj.TapeID {
|
||||
return ii.TapeID < jj.TapeID
|
||||
}
|
||||
if ii.Path != jj.Path {
|
||||
return strings.ReplaceAll(ii.Path, "/", "\x00") < strings.ReplaceAll(jj.Path, "/", "\x00")
|
||||
}
|
||||
return ii.WriteTime.After(jj.WriteTime)
|
||||
})
|
||||
for idx, posi := range posis {
|
||||
if idx == 0 {
|
||||
continue
|
||||
}
|
||||
if posis[idx-1].TapeID == posi.TapeID && posis[idx-1].Path == posi.Path {
|
||||
needDeletePositionIDs = append(needDeletePositionIDs, posi.ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(needDeleteFileIDs) > 0 {
|
||||
if r := l.db.WithContext(ctx).Where("id IN (?)", needDeleteFileIDs).Delete(ModelFile); r.Error != nil {
|
||||
return fmt.Errorf("delete files fail, err= %w", r.Error)
|
||||
}
|
||||
}
|
||||
if len(needDeletePositionIDs) > 0 {
|
||||
if r := l.db.WithContext(ctx).Where("id IN (?)", needDeletePositionIDs).Delete(ModelPosition); r.Error != nil {
|
||||
return fmt.Errorf("delete positions fail, err= %w", r.Error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user