github.com/cozy/cozy-stack@v0.0.0-20240603063001-31110fa4cae1/worker/trash/trash.go (about)

     1  package trash
     2  
     3  import (
     4  	"fmt"
     5  	"runtime"
     6  	"time"
     7  
     8  	"github.com/cozy/cozy-stack/model/job"
     9  	"github.com/cozy/cozy-stack/model/vfs"
    10  	"github.com/cozy/cozy-stack/pkg/config/config"
    11  	"github.com/cozy/cozy-stack/pkg/consts"
    12  	"github.com/cozy/cozy-stack/pkg/couchdb"
    13  	"github.com/cozy/cozy-stack/pkg/couchdb/mango"
    14  	"github.com/hashicorp/go-multierror"
    15  	"github.com/justincampbell/bigduration"
    16  )
    17  
    18  func init() {
    19  	job.AddWorker(&job.WorkerConfig{
    20  		WorkerType:   "trash-files",
    21  		Concurrency:  runtime.NumCPU() * 4,
    22  		MaxExecCount: 2,
    23  		Reserved:     true,
    24  		Timeout:      2 * time.Hour,
    25  		WorkerFunc:   WorkerTrashFiles,
    26  	})
    27  
    28  	job.AddWorker(&job.WorkerConfig{
    29  		WorkerType:   "clean-old-trashed",
    30  		Concurrency:  runtime.NumCPU() * 4,
    31  		MaxExecCount: 2,
    32  		Reserved:     true,
    33  		Timeout:      2 * time.Hour,
    34  		WorkerFunc:   WorkerCleanOldTrashed,
    35  	})
    36  }
    37  
    38  // WorkerTrashFiles is a worker to remove files in Swift after they have been
    39  // removed from CouchDB. It is used when cleaning the trash, as removing a lot
    40  // of files from Swift can take some time.
    41  func WorkerTrashFiles(ctx *job.TaskContext) error {
    42  	opts := vfs.TrashJournal{}
    43  	if err := ctx.UnmarshalMessage(&opts); err != nil {
    44  		return err
    45  	}
    46  	fs := ctx.Instance.VFS()
    47  	if err := fs.EnsureErased(opts); err != nil {
    48  		ctx.Logger().WithField("critical", "true").
    49  			Errorf("Error: %s", err)
    50  		return err
    51  	}
    52  	return nil
    53  }
    54  
    55  // WorkerCleanOldTrashed is a worker used to automatically delete files and
    56  // directories that are in the trash for too long. The threshold for deletion
    57  // is configurable per context in the config file, via the
    58  // fs.auto_clean_trashed_after parameter.
    59  func WorkerCleanOldTrashed(ctx *job.TaskContext) error {
    60  	cfg := config.GetConfig().Fs.AutoCleanTrashedAfter
    61  	after, ok := cfg[ctx.Instance.ContextName]
    62  	if !ok || after == "" {
    63  		return nil
    64  	}
    65  	delay, err := bigduration.ParseDuration(after)
    66  	if err != nil {
    67  		ctx.Logger().WithField("critical", "true").
    68  			Errorf("Invalid config for auto_clean_trashed_after: %s", err)
    69  		return err
    70  	}
    71  	before := time.Now().Add(-delay)
    72  
    73  	var list []*vfs.DirOrFileDoc
    74  	sel := mango.And(
    75  		mango.Equal("dir_id", consts.TrashDirID),
    76  		mango.Lt("updated_at", before),
    77  	)
    78  	req := &couchdb.FindRequest{
    79  		UseIndex: "by-dir-id-updated-at",
    80  		Selector: sel,
    81  		Limit:    1000,
    82  	}
    83  	if _, err := couchdb.FindDocsRaw(ctx.Instance, consts.Files, req, &list); err != nil {
    84  		return err
    85  	}
    86  
    87  	var errm error
    88  	fs := ctx.Instance.VFS()
    89  	push := pushTrashJob(fs)
    90  	for _, item := range list {
    91  		d, f := item.Refine()
    92  		if f != nil {
    93  			err = fs.DestroyFile(f)
    94  		} else if d != nil {
    95  			err = fs.DestroyDirAndContent(d, push)
    96  		} else {
    97  			err = fmt.Errorf("Invalid type for %v", item)
    98  		}
    99  		if err != nil {
   100  			errm = multierror.Append(errm, err)
   101  		}
   102  	}
   103  	return errm
   104  }
   105  
   106  func pushTrashJob(fs vfs.VFS) func(vfs.TrashJournal) error {
   107  	return func(journal vfs.TrashJournal) error {
   108  		return fs.EnsureErased(journal)
   109  	}
   110  }