From 08453a2c9969f24cdba0f2092c1e8fd967d5ccd8 Mon Sep 17 00:00:00 2001 From: Abhishek Shroff Date: Thu, 4 Sep 2025 18:24:05 +0530 Subject: [PATCH] [server][img] Create functionality for copying imgs. Needs to be wired --- server/internal/command/command.go | 1 + server/internal/core/resource_copy_move.go | 21 ++++++++++++ server/internal/core/resource_create.go | 10 +++--- server/internal/core/version.go | 2 +- server/internal/img/preview.go | 19 ++++++++--- server/internal/img/resize.go | 2 +- server/internal/jobs/copy_imgs.go | 39 ++++++++++++++++++++++ 7 files changed, 84 insertions(+), 10 deletions(-) create mode 100644 server/internal/jobs/copy_imgs.go diff --git a/server/internal/command/command.go b/server/internal/command/command.go index 3081a217..fa36c859 100644 --- a/server/internal/command/command.go +++ b/server/internal/command/command.go @@ -135,6 +135,7 @@ func SetupCommand() { client := steve.Initialize(db.Get(ctx), cfg.Steve, logger) steve.RegisterWorker(client, &jobs.MigrateWorker{}) + steve.RegisterWorker(client, &jobs.CopyImgsWorker{}) steve.RegisterWorker(client, &jobs.CopyContentsWorker{}) steve.RegisterWorker(client, &jobs.DeleteContentsWorker{}) } diff --git a/server/internal/core/resource_copy_move.go b/server/internal/core/resource_copy_move.go index 65bf5622..b25d04d0 100644 --- a/server/internal/core/resource_copy_move.go +++ b/server/internal/core/resource_copy_move.go @@ -174,6 +174,7 @@ func (f txFileSystem) Copy(src Resource, target string, requestedID uuid.UUID, r createResources := make([]insertResourcesFastParams, 0, len(tree)) var createVersions []insertResourceVersionsFastParams var copyContents []jobs.CopyContentsArgs + var copyImgs []jobs.CopyImgsArgs var migrateContents []jobs.MigrateArgs newIDs := make(map[uuid.UUID]uuid.UUID) @@ -204,6 +205,7 @@ func (f txFileSystem) Copy(src Resource, target string, requestedID uuid.UUID, r Size: int32(src.latestVersionInfo.Size), MimeType: src.latestVersionInfo.MimeType, SHA256: src.latestVersionInfo.SHA256, + ImgRes: src.latestVersionInfo.ImgRes, }) v := []VersionInfo{{ ID: versionID, @@ -211,8 +213,14 @@ func (f txFileSystem) Copy(src Resource, target string, requestedID uuid.UUID, r Size: src.latestVersionInfo.Size, MimeType: src.latestVersionInfo.MimeType, SHA256: src.latestVersionInfo.SHA256, + ImgRes: src.latestVersionInfo.ImgRes, }} dest.versions, _ = json.Marshal(v) + copyImgs = append(copyImgs, jobs.CopyImgsArgs{ + Src: src.latestVersionInfo.ID, + Dest: versionID, + ImgRes: src.latestVersionInfo.ImgRes, + }) copyContents = append(copyContents, jobs.CopyContentsArgs{ Src: src.latestVersionInfo.ID, Dest: versionID, @@ -243,6 +251,16 @@ func (f txFileSystem) Copy(src Resource, target string, requestedID uuid.UUID, r Size: int32(src.latestVersionInfo.Size), MimeType: src.latestVersionInfo.MimeType, SHA256: src.latestVersionInfo.SHA256, + ImgRes: src.latestVersionInfo.ImgRes, + }) + copyImgs = append(copyImgs, jobs.CopyImgsArgs{ + Src: src.latestVersionInfo.ID, + Dest: versionID, + ImgRes: src.latestVersionInfo.ImgRes, + }) + copyContents = append(copyContents, jobs.CopyContentsArgs{ + Src: src.latestVersionInfo.ID, + Dest: versionID, }) migrateContents = append(migrateContents, jobs.MigrateArgs{ VersionID: versionID, @@ -265,6 +283,9 @@ func (f txFileSystem) Copy(src Resource, target string, requestedID uuid.UUID, r } } + if err := jobs.CopyImgsMany(f.db, copyImgs); err != nil { + return Resource{}, false, err + } if err := jobs.CopyContents(f.db, copyContents); err != nil { return Resource{}, false, err } diff --git a/server/internal/core/resource_create.go b/server/internal/core/resource_create.go index c71abb89..9314f9ee 100644 --- a/server/internal/core/resource_create.go +++ b/server/internal/core/resource_create.go @@ -67,7 +67,7 @@ func (f *FileSystem) CreateFileByPath(path string, requestedID, versionID uuid.U } else { return computeProps(dest, func(len int, hash hash.Hash, mimeType string) error { sum := hex.EncodeToString(hash.Sum(nil)) - var generated int8 + var generated uint8 if generated, err = imgr.Generate(backend.Path(versionID.String()), mimeType); err != nil { return err } @@ -114,7 +114,7 @@ func (f *FileSystem) CreateFileVersion(r Resource, versionID uuid.UUID) (io.Writ } else { return computeProps(dest, func(len int, hash hash.Hash, mimeType string) error { sum := hex.EncodeToString(hash.Sum(nil)) - var generated int8 + var generated uint8 if generated, err = imgr.Generate(backend.Path(versionID.String()), mimeType); err != nil { return err } @@ -374,7 +374,7 @@ func updateResourceModified(db db.TxHandler, id uuid.UUID) error { return err } -func insertResourceVersion(db db.TxHandler, id, versionID uuid.UUID, size int64, mimeType, sha256 string, imgres int8) error { +func insertResourceVersion(db db.TxHandler, id, versionID uuid.UUID, size int64, mimeType, sha256 string, imgres uint8) error { const q = `INSERT INTO resource_versions(id, resource_id, size, mime_type, sha256, storage, imgres) VALUES (@version_id, @resource_id, @size, @mime_type, @sha256, @storage, @imgres)` @@ -438,7 +438,7 @@ func (r iteratorForInsertResourcesFast) Err() error { } func insertResourceVersionsFast(db db.TxHandler, arg []insertResourceVersionsFastParams) (int64, error) { - return db.CopyFrom([]string{"resource_versions"}, []string{"id", "resource_id", "size", "mime_type", "sha256", "storage"}, &iteratorForInsertResourceVersionsFast{rows: arg}) + return db.CopyFrom([]string{"resource_versions"}, []string{"id", "resource_id", "size", "mime_type", "sha256", "imgres", "storage"}, &iteratorForInsertResourceVersionsFast{rows: arg}) } // For bulk insert @@ -448,6 +448,7 @@ type insertResourceVersionsFastParams struct { Size int32 MimeType string SHA256 string + ImgRes uint8 } // iteratorForInsertResourceVersionsFast implements pgx.CopyFromSource. @@ -475,6 +476,7 @@ func (r iteratorForInsertResourceVersionsFast) Values() ([]interface{}, error) { r.rows[0].Size, r.rows[0].MimeType, r.rows[0].SHA256, + r.rows[0].ImgRes, storage.DefaultBackendName, }, nil } diff --git a/server/internal/core/version.go b/server/internal/core/version.go index 1e5512a7..c286396b 100644 --- a/server/internal/core/version.go +++ b/server/internal/core/version.go @@ -19,7 +19,7 @@ type VersionInfo struct { Size int64 `json:"size"` MimeType string `json:"mime_type"` SHA256 string `json:"sha256"` - ImgRes int8 `json:"imgres"` + ImgRes uint8 `json:"imgres"` } type Version struct { diff --git a/server/internal/img/preview.go b/server/internal/img/preview.go index 9e63a45d..75ddb591 100644 --- a/server/internal/img/preview.go +++ b/server/internal/img/preview.go @@ -41,7 +41,18 @@ func (g *Imgr) Open(id string, res Res) (io.ReadCloser, error) { return os.Open(filepath.Join(g.dir, id) + "-" + resSuffixes[res] + ".webp") } -func (g *Imgr) Generate(path, mimeType string) (int8, error) { +func (g *Imgr) Copy(src, dest string, res Res) error { + if in, err := os.Open(filepath.Join(g.dir, src) + "-" + resSuffixes[res] + ".webp"); err != nil { + return err + } else if out, err := os.Create(filepath.Join(g.dir, src) + "-" + resSuffixes[res] + ".webp"); err != nil { + return err + } else if _, err := io.Copy(out, in); err != nil { + return err + } + return nil +} + +func (g *Imgr) Generate(path, mimeType string) (Res, error) { if imageType, ok := strings.CutPrefix(mimeType, "image/"); ok { if _, ok := imageTypes[imageType]; ok { return g.processImage(path) @@ -70,7 +81,7 @@ func (g *Imgr) Generate(path, mimeType string) (int8, error) { // processImage generates preview + thumbnail for images (and PDF). // Preview is only generated if the image size is larger than 1M -func (g *Imgr) processImage(input string) (int8, error) { +func (g *Imgr) processImage(input string) (Res, error) { var generated Res stat, err := os.Stat(input) if err != nil { @@ -96,7 +107,7 @@ func (g *Imgr) processImage(input string) (int8, error) { // Generate thumbnail only for text using. // A temporary document preview must be generated and then resized down -func (g *Imgr) processText(input string) (int8, error) { +func (g *Imgr) processText(input string) (Res, error) { if err := generateTextPreview(input, g.tmp); err != nil { return 0, err } @@ -113,7 +124,7 @@ func (g *Imgr) processText(input string) (int8, error) { } // Generate preview and thumbnail for office documents. -func (g *Imgr) processDocument(input string) (int8, error) { +func (g *Imgr) processDocument(input string) (Res, error) { if err := generateDocumentPreview(input, g.dir); err != nil { return 0, err } diff --git a/server/internal/img/resize.go b/server/internal/img/resize.go index 6a8e0a5a..d1e65617 100644 --- a/server/internal/img/resize.go +++ b/server/internal/img/resize.go @@ -8,7 +8,7 @@ import ( "strconv" ) -type Res = int8 +type Res = uint8 const ( ResThumbnail Res = 1 diff --git a/server/internal/jobs/copy_imgs.go b/server/internal/jobs/copy_imgs.go new file mode 100644 index 00000000..9dd3159e --- /dev/null +++ b/server/internal/jobs/copy_imgs.go @@ -0,0 +1,39 @@ +package jobs + +import ( + "context" + + "codeberg.org/shroff/phylum/server/internal/db" + "codeberg.org/shroff/phylum/server/internal/steve" + "github.com/google/uuid" +) + +type CopyImgsArgs struct { + Src uuid.UUID `json:"src"` + Dest uuid.UUID `json:"dest"` + ImgRes uint8 `json:"imgres"` +} + +func (a CopyImgsArgs) Kind() string { return "copy_imgs" } +func (a CopyImgsArgs) Sequences() []string { return []string{a.Src.String(), a.Dest.String()} } + +type CopyImgsWorker struct { + steve.WorkerDefaults[CopyImgsArgs] +} + +func (w *CopyImgsWorker) Work(ctx context.Context, job *steve.Job[CopyImgsArgs]) error { + return copyImgs(ctx, job.Args.Src, job.Args.Dest, job.Args.ImgRes) +} + +func CopyImgsMany(db db.Handler, args []CopyImgsArgs) error { + params := make([]steve.JobArgs, len(args)) + for i, a := range args { + params[i] = a + } + return steve.Get().InsertJobs(db, params) +} + +func copyImgs(ctx context.Context, src, dest uuid.UUID, imgRes uint8) error { + // TODO: implement + return nil +}