mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-09-12 13:49:13 -04:00
refactor(thumbnails): thread context.Context through the preprocessor Convert interface
The Tika preview extractor does a network call; it was using context.Background(). Pass the request context from the gRPC handler through Convert so the unpack call respects cancellation and deadlines. Non-I/O decoders ignore the context.
This commit is contained in:
1 parent
c286f771c9
commit
75893c19ee
8 files changed
+40
-34
No files matched your search
@@ -4,6 +4,7 @@ import (
|
||||
"archive/zip"
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"image"
|
||||
@@ -26,14 +27,14 @@ import (
|
||||
|
||||
// FileConverter is the interface for the file converter
|
||||
type FileConverter interface {
|
||||
Convert(r io.Reader) (any, error)
|
||||
Convert(ctx context.Context, r io.Reader) (any, error)
|
||||
}
|
||||
|
||||
// GifDecoder is a converter for the gif file
|
||||
type GifDecoder struct{}
|
||||
|
||||
// Convert reads the gif file and returns the thumbnail image
|
||||
func (i GifDecoder) Convert(r io.Reader) (any, error) {
|
||||
func (i GifDecoder) Convert(_ context.Context, r io.Reader) (any, error) {
|
||||
img, err := gif.DecodeAll(r)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, `could not decode the image`)
|
||||
@@ -45,7 +46,7 @@ func (i GifDecoder) Convert(r io.Reader) (any, error) {
|
||||
type GgsDecoder struct{ thumbnailpath string }
|
||||
|
||||
// Convert reads the ggs file and returns the thumbnail image
|
||||
func (g GgsDecoder) Convert(r io.Reader) (any, error) {
|
||||
func (g GgsDecoder) Convert(ctx context.Context, r io.Reader) (any, error) {
|
||||
var buf bytes.Buffer
|
||||
_, err := io.Copy(&buf, r)
|
||||
if err != nil {
|
||||
@@ -65,7 +66,7 @@ func (g GgsDecoder) Convert(r io.Reader) (any, error) {
|
||||
if converter == nil {
|
||||
return nil, thumbnailerErrors.ErrNoConverterForExtractedImageFromGgsFile
|
||||
}
|
||||
img, err := converter.Convert(thumbnail)
|
||||
img, err := converter.Convert(ctx, thumbnail)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, `could not decode the image`)
|
||||
}
|
||||
@@ -79,7 +80,7 @@ func (g GgsDecoder) Convert(r io.Reader) (any, error) {
|
||||
type AudioDecoder struct{}
|
||||
|
||||
// Convert reads the audio file and extracts the thumbnail image from the id3 tag
|
||||
func (i AudioDecoder) Convert(r io.Reader) (any, error) {
|
||||
func (i AudioDecoder) Convert(ctx context.Context, r io.Reader) (any, error) {
|
||||
b, err := io.ReadAll(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -99,7 +100,7 @@ func (i AudioDecoder) Convert(r io.Reader) (any, error) {
|
||||
return nil, thumbnailerErrors.ErrNoConverterForExtractedImageFromAudioFile
|
||||
}
|
||||
|
||||
return converter.Convert(bytes.NewReader(picture.Data))
|
||||
return converter.Convert(ctx, bytes.NewReader(picture.Data))
|
||||
}
|
||||
|
||||
// TxtToImageConverter is a converter for the text file
|
||||
@@ -108,7 +109,7 @@ type TxtToImageConverter struct {
|
||||
}
|
||||
|
||||
// Convert reads the text file and renders it into a thumbnail image
|
||||
func (t TxtToImageConverter) Convert(r io.Reader) (any, error) {
|
||||
func (t TxtToImageConverter) Convert(_ context.Context, r io.Reader) (any, error) {
|
||||
img := image.NewRGBA(image.Rect(0, 0, 640, 480))
|
||||
|
||||
imgBounds := img.Bounds()
|
||||
@@ -203,7 +204,7 @@ type GGPStruct struct {
|
||||
type GgpDecoder struct{}
|
||||
|
||||
// Convert reads the ggp file and returns the first thumbnail image
|
||||
func (j GgpDecoder) Convert(r io.Reader) (any, error) {
|
||||
func (j GgpDecoder) Convert(_ context.Context, r io.Reader) (any, error) {
|
||||
ggp := &GGPStruct{}
|
||||
err := json.NewDecoder(r).Decode(ggp)
|
||||
if err != nil {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
package preprocessor
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"github.com/kovidgoyal/imaging"
|
||||
@@ -13,7 +14,7 @@ import (
|
||||
type ImageDecoder struct{}
|
||||
|
||||
// Convert reads the image file and returns the thumbnail image
|
||||
func (i ImageDecoder) Convert(r io.Reader) (any, error) {
|
||||
func (i ImageDecoder) Convert(_ context.Context, r io.Reader) (any, error) {
|
||||
img, err := imaging.Decode(r, imaging.AutoOrientation(true))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, `could not decode the image`)
|
||||
|
||||
@@ -2,6 +2,7 @@ package preprocessor
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"io"
|
||||
"os"
|
||||
"testing"
|
||||
@@ -32,14 +33,14 @@ var _ = Describe("ImageDecoder", func() {
|
||||
|
||||
It("should decode an image", func() {
|
||||
decoder := ImageDecoder{}
|
||||
img, err := decoder.Convert(fileReader)
|
||||
img, err := decoder.Convert(context.TODO(), fileReader)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(img).ToNot(BeNil())
|
||||
})
|
||||
|
||||
It("should return an error if the image is invalid", func() {
|
||||
decoder := ImageDecoder{}
|
||||
img, err := decoder.Convert(bytes.NewReader([]byte("not an image")))
|
||||
img, err := decoder.Convert(context.TODO(), bytes.NewReader([]byte("not an image")))
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(img).To(BeNil())
|
||||
})
|
||||
@@ -57,14 +58,14 @@ var _ = Describe("ImageDecoder", func() {
|
||||
|
||||
It("should decode a gif", func() {
|
||||
decoder := GifDecoder{}
|
||||
img, err := decoder.Convert(fileReader)
|
||||
img, err := decoder.Convert(context.TODO(), fileReader)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(img).ToNot(BeNil())
|
||||
})
|
||||
|
||||
It("should return an error if the gif is invalid", func() {
|
||||
decoder := GifDecoder{}
|
||||
img, err := decoder.Convert(bytes.NewReader([]byte("not a gif")))
|
||||
img, err := decoder.Convert(context.TODO(), bytes.NewReader([]byte("not a gif")))
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(img).To(BeNil())
|
||||
})
|
||||
@@ -82,14 +83,14 @@ var _ = Describe("ImageDecoder", func() {
|
||||
|
||||
It("should decode a ggs", func() {
|
||||
decoder := GgsDecoder{"_slide0/geogebra_thumbnail.png"}
|
||||
img, err := decoder.Convert(fileReader)
|
||||
img, err := decoder.Convert(context.TODO(), fileReader)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(img).ToNot(BeNil())
|
||||
})
|
||||
|
||||
It("should return an error if the ggs is invalid", func() {
|
||||
decoder := GgsDecoder{"_slide0/geogebra_thumbnail.png"}
|
||||
img, err := decoder.Convert(bytes.NewReader([]byte("not a ggs")))
|
||||
img, err := decoder.Convert(context.TODO(), bytes.NewReader([]byte("not a ggs")))
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(img).To(BeNil())
|
||||
})
|
||||
@@ -104,7 +105,7 @@ var _ = Describe("ImageDecoder", func() {
|
||||
}
|
||||
fileReader = bytes.NewReader(fileContent)
|
||||
decoder := AudioDecoder{}
|
||||
img, err := decoder.Convert(fileReader)
|
||||
img, err := decoder.Convert(context.TODO(), fileReader)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(img).ToNot(BeNil())
|
||||
})
|
||||
@@ -115,13 +116,13 @@ var _ = Describe("ImageDecoder", func() {
|
||||
}
|
||||
fileReader = bytes.NewReader(fileContent)
|
||||
decoder := AudioDecoder{}
|
||||
img, err := decoder.Convert(fileReader)
|
||||
img, err := decoder.Convert(context.TODO(), fileReader)
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(img).To(BeNil())
|
||||
})
|
||||
It("should return an error if the audio is invalid", func() {
|
||||
decoder := AudioDecoder{}
|
||||
img, err := decoder.Convert(bytes.NewReader([]byte("not an audio")))
|
||||
img, err := decoder.Convert(context.TODO(), bytes.NewReader([]byte("not an audio")))
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(img).To(BeNil())
|
||||
})
|
||||
@@ -145,7 +146,7 @@ var _ = Describe("ImageDecoder", func() {
|
||||
}
|
||||
})
|
||||
It("should decode a text", func() {
|
||||
img, err := decoder.Convert(bytes.NewReader([]byte("This is a test text")))
|
||||
img, err := decoder.Convert(context.TODO(), bytes.NewReader([]byte("This is a test text")))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(img).ToNot(BeNil())
|
||||
})
|
||||
@@ -156,7 +157,7 @@ var _ = Describe("ImageDecoder", func() {
|
||||
DefaultFont: "/some/unknown/font.otf",
|
||||
},
|
||||
}
|
||||
img, err := decoder.Convert(bytes.NewReader([]byte("This is a test text")))
|
||||
img, err := decoder.Convert(context.TODO(), bytes.NewReader([]byte("This is a test text")))
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(img).To(BeNil())
|
||||
})
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
package preprocessor
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"github.com/davidbyttow/govips/v2/vips"
|
||||
@@ -14,7 +15,7 @@ func init() {
|
||||
|
||||
type ImageDecoder struct{}
|
||||
|
||||
func (v ImageDecoder) Convert(r io.Reader) (interface{}, error) {
|
||||
func (v ImageDecoder) Convert(_ context.Context, r io.Reader) (interface{}, error) {
|
||||
img, err := vips.NewImageFromReader(r)
|
||||
return img, err
|
||||
}
|
||||
@@ -27,16 +27,16 @@ type TikaDecoder struct {
|
||||
filename string
|
||||
}
|
||||
|
||||
func (d TikaDecoder) Convert(r io.Reader) (any, error) {
|
||||
func (d TikaDecoder) Convert(ctx context.Context, r io.Reader) (any, error) {
|
||||
data, err := io.ReadAll(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
preview, err := tikaExtractPreview(context.Background(), d.tikaURL, d.filename, data)
|
||||
preview, err := tikaExtractPreview(ctx, d.tikaURL, d.filename, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ForType("image/jpeg", nil).Convert(bytes.NewReader(preview))
|
||||
return ForType("image/jpeg", nil).Convert(ctx, bytes.NewReader(preview))
|
||||
}
|
||||
|
||||
var tikaHTTPClient = &http.Client{Timeout: 30 * time.Second}
|
||||
|
||||
@@ -3,6 +3,7 @@ package preprocessor
|
||||
import (
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"context"
|
||||
"image"
|
||||
"image/jpeg"
|
||||
"io"
|
||||
@@ -62,7 +63,7 @@ var _ = Describe("TikaDecoder", func() {
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
img, err := TikaDecoder{tikaURL: srv.URL}.Convert(bytes.NewReader([]byte("raw")))
|
||||
img, err := TikaDecoder{tikaURL: srv.URL}.Convert(context.TODO(), bytes.NewReader([]byte("raw")))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
// default (imaging) build decodes to an image.Image
|
||||
bounds := img.(image.Image).Bounds()
|
||||
@@ -76,7 +77,7 @@ var _ = Describe("TikaDecoder", func() {
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
_, err := TikaDecoder{tikaURL: srv.URL}.Convert(bytes.NewReader([]byte("raw")))
|
||||
_, err := TikaDecoder{tikaURL: srv.URL}.Convert(context.TODO(), bytes.NewReader([]byte("raw")))
|
||||
Expect(err).To(MatchError(thumbnailerErrors.ErrNoImageFromRawFile))
|
||||
})
|
||||
|
||||
@@ -86,7 +87,7 @@ var _ = Describe("TikaDecoder", func() {
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
_, err := TikaDecoder{tikaURL: srv.URL}.Convert(bytes.NewReader([]byte("raw")))
|
||||
_, err := TikaDecoder{tikaURL: srv.URL}.Convert(context.TODO(), bytes.NewReader([]byte("raw")))
|
||||
Expect(err).To(HaveOccurred())
|
||||
})
|
||||
|
||||
@@ -98,7 +99,7 @@ var _ = Describe("TikaDecoder", func() {
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
_, err := TikaDecoder{tikaURL: srv.URL, filename: "my photo.nef"}.Convert(bytes.NewReader([]byte("raw")))
|
||||
_, err := TikaDecoder{tikaURL: srv.URL, filename: "my photo.nef"}.Convert(context.TODO(), bytes.NewReader([]byte("raw")))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(gotCD).To(Equal(`attachment; filename="my photo.nef"`))
|
||||
})
|
||||
@@ -112,7 +113,7 @@ var _ = Describe("TikaDecoder", func() {
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
img, err := TikaDecoder{tikaURL: srv.URL}.Convert(bytes.NewReader([]byte("raw")))
|
||||
img, err := TikaDecoder{tikaURL: srv.URL}.Convert(context.TODO(), bytes.NewReader([]byte("raw")))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(img.(image.Image).Bounds().Dx()).To(Equal(16))
|
||||
})
|
||||
@@ -123,7 +124,7 @@ var _ = Describe("TikaDecoder", func() {
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
_, err := TikaDecoder{tikaURL: srv.URL}.Convert(bytes.NewReader([]byte("raw")))
|
||||
_, err := TikaDecoder{tikaURL: srv.URL}.Convert(context.TODO(), bytes.NewReader([]byte("raw")))
|
||||
Expect(err).To(MatchError(thumbnailerErrors.ErrNoImageFromRawFile))
|
||||
})
|
||||
|
||||
@@ -133,7 +134,7 @@ var _ = Describe("TikaDecoder", func() {
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
_, err := TikaDecoder{tikaURL: srv.URL}.Convert(bytes.NewReader([]byte("raw")))
|
||||
_, err := TikaDecoder{tikaURL: srv.URL}.Convert(context.TODO(), bytes.NewReader([]byte("raw")))
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(err).ToNot(MatchError(thumbnailerErrors.ErrNoImageFromRawFile))
|
||||
})
|
||||
|
||||
@@ -173,7 +173,7 @@ func (g Thumbnail) handleCS3Source(ctx context.Context, req *thumbnailssvc.GetTh
|
||||
"filename": sRes.GetInfo().GetName(),
|
||||
}
|
||||
pp := preprocessor.ForType(sRes.GetInfo().GetMimeType(), ppOpts)
|
||||
img, err := pp.Convert(r)
|
||||
img, err := pp.Convert(ctx, r)
|
||||
switch {
|
||||
case errors.Is(err, terrors.ErrNoImageFromRawFile):
|
||||
// a raw file without an embedded preview is expected, not an error
|
||||
@@ -275,7 +275,7 @@ func (g Thumbnail) handleWebdavSource(ctx context.Context, req *thumbnailssvc.Ge
|
||||
"filename": sRes.GetInfo().GetName(),
|
||||
}
|
||||
pp := preprocessor.ForType(sRes.GetInfo().GetMimeType(), ppOpts)
|
||||
img, err := pp.Convert(r)
|
||||
img, err := pp.Convert(ctx, r)
|
||||
if img == nil || err != nil {
|
||||
return "", merrors.NotFound(g.serviceID, "could not get image")
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package thumbnail
|
||||
|
||||
import (
|
||||
"context"
|
||||
"image"
|
||||
"os"
|
||||
"path"
|
||||
@@ -176,7 +177,7 @@ func TestPreviewGenerationTooBigImage(t *testing.T) {
|
||||
defer f.Close()
|
||||
|
||||
preproc := preprocessor.ForType(tt.mimeType, nil)
|
||||
convert, err := preproc.Convert(f)
|
||||
convert, err := preproc.Convert(context.TODO(), f)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user