diff --git a/cmd/telesrv/main.go b/cmd/telesrv/main.go index 87a705c7..ca78cf4e 100644 --- a/cmd/telesrv/main.go +++ b/cmd/telesrv/main.go @@ -765,6 +765,7 @@ func run(logger *zap.Logger) error { filesService := filesapp.NewService(mediaStore, blobBackend, cfg.DC, filesapp.WithLogger(logger), filesapp.WithGifCatalog(gifCatalogStore), + filesapp.WithGifSeedDir(cfg.GifSeedDir), filesapp.WithUploadPartQuota(domain.UploadPartQuota{ MaxBytes: cfg.UploadInFlightMaxBytes, MaxParts: cfg.UploadInFlightMaxParts, diff --git a/internal/app/files/gif_admin.go b/internal/app/files/gif_admin.go index 5c6c1440..6a43e6ec 100644 --- a/internal/app/files/gif_admin.go +++ b/internal/app/files/gif_admin.go @@ -4,6 +4,8 @@ import ( "context" "crypto/sha256" "fmt" + "os" + "path/filepath" "strings" "time" @@ -281,11 +283,22 @@ func (s *Service) AdminDeleteUncategorizedGifs(ctx context.Context) (deletedEntr if err != nil { s.log.Warn("delete uncategorized gif document failed", zap.Int64("catalog_entry_id", e.ID), zap.Int64("document_id", e.DocumentID), zap.Error(err)) - continue - } - if deleted { + } else if deleted { deletedDocuments++ } + // SeedGifs re-imports any file under the seed dir that doesn't have a + // matching gif_catalog row (that's the whole point -- drop a new file + // in, it shows up on next restart), so a seed-imported entry's source + // file has to go too, or the next restart just re-imports the very + // gif this call deleted. Admin-panel uploads never set + // SourceFilename, so this is a no-op for those. + if e.SourceFilename != "" && s.gifSeedDir != "" { + path := filepath.Join(s.gifSeedDir, e.SourceFilename) + if err := os.Remove(path); err != nil && !os.IsNotExist(err) { + s.log.Warn("delete uncategorized gif seed file failed", + zap.Int64("catalog_entry_id", e.ID), zap.String("path", path), zap.Error(err)) + } + } } return deletedEntries, deletedDocuments, nil } diff --git a/internal/app/files/service.go b/internal/app/files/service.go index 84f34f66..52e1b307 100644 --- a/internal/app/files/service.go +++ b/internal/app/files/service.go @@ -89,6 +89,13 @@ type Service struct { premiumPromoReady bool gifCatalog store.GifCatalogStore + // gifSeedDir is cfg.GifSeedDir, the same root SeedGifs scans at startup. + // AdminDeleteUncategorizedGifs needs it too: a seed-imported entry's + // underlying file still sits in this directory, and SeedGifs re-imports + // any file there without a matching gif_catalog row on the very next + // restart -- deleting only the DB row would make a "deleted" GIF come + // back on its own. + gifSeedDir string } // Option 配置 files 服务的可选能力。 @@ -180,6 +187,16 @@ func WithGifCatalog(c store.GifCatalogStore) Option { } } +// WithGifSeedDir records the gif seed directory (cfg.GifSeedDir) so +// AdminDeleteUncategorizedGifs can remove a seed-imported entry's source +// file alongside its DB row -- see the field's doc comment for why that +// matters. +func WithGifSeedDir(dir string) Option { + return func(s *Service) { + s.gifSeedDir = dir + } +} + // NewService 创建 files 服务。dc 是本 server 的 DC id,写入新建 document/photo 的 dc_id。 func NewService(media store.MediaStore, blobs BlobBackend, dc int, opts ...Option) *Service { s := &Service{