mirror of
https://github.com/imgproxy/imgproxy.git
synced 2025-10-06 18:03:29 +02:00
Provide shared resources to handlers via HandlerContext interface
This commit is contained in:
committed by
Sergei Aleksandrovich
parent
adb4341713
commit
53645688fb
@@ -19,25 +19,27 @@ import (
|
|||||||
"github.com/imgproxy/imgproxy/v3/semaphores"
|
"github.com/imgproxy/imgproxy/v3/semaphores"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// HandlerContext provides access to shared handler dependencies
|
||||||
|
type HandlerContext interface {
|
||||||
|
HeaderWriter() *headerwriter.Writer
|
||||||
|
Semaphores() *semaphores.Semaphores
|
||||||
|
FallbackImage() auximageprovider.Provider
|
||||||
|
WatermarkImage() auximageprovider.Provider
|
||||||
|
ImageDataFactory() *imagedata.Factory
|
||||||
|
}
|
||||||
|
|
||||||
// Handler handles image processing requests
|
// Handler handles image processing requests
|
||||||
type Handler struct {
|
type Handler struct {
|
||||||
hw *headerwriter.Writer // Configured HeaderWriter instance
|
HandlerContext
|
||||||
stream *stream.Handler // Stream handler for raw image streaming
|
|
||||||
config *Config // Handler configuration
|
stream *stream.Handler // Stream handler for raw image streaming
|
||||||
semaphores *semaphores.Semaphores
|
config *Config // Handler configuration
|
||||||
fallbackImage auximageprovider.Provider
|
|
||||||
watermarkImage auximageprovider.Provider
|
|
||||||
idf *imagedata.Factory
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates new handler object
|
// New creates new handler object
|
||||||
func New(
|
func New(
|
||||||
|
hCtx HandlerContext,
|
||||||
stream *stream.Handler,
|
stream *stream.Handler,
|
||||||
hw *headerwriter.Writer,
|
|
||||||
semaphores *semaphores.Semaphores,
|
|
||||||
fi auximageprovider.Provider,
|
|
||||||
wi auximageprovider.Provider,
|
|
||||||
idf *imagedata.Factory,
|
|
||||||
config *Config,
|
config *Config,
|
||||||
) (*Handler, error) {
|
) (*Handler, error) {
|
||||||
if err := config.Validate(); err != nil {
|
if err := config.Validate(); err != nil {
|
||||||
@@ -45,13 +47,9 @@ func New(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &Handler{
|
return &Handler{
|
||||||
hw: hw,
|
HandlerContext: hCtx,
|
||||||
config: config,
|
config: config,
|
||||||
stream: stream,
|
stream: stream,
|
||||||
semaphores: semaphores,
|
|
||||||
fallbackImage: fi,
|
|
||||||
watermarkImage: wi,
|
|
||||||
idf: idf,
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,49 +57,48 @@ func New(
|
|||||||
func (h *Handler) Execute(
|
func (h *Handler) Execute(
|
||||||
reqID string,
|
reqID string,
|
||||||
rw http.ResponseWriter,
|
rw http.ResponseWriter,
|
||||||
imageRequest *http.Request,
|
req *http.Request,
|
||||||
) error {
|
) error {
|
||||||
// Increment the number of requests in progress
|
// Increment the number of requests in progress
|
||||||
stats.IncRequestsInProgress()
|
stats.IncRequestsInProgress()
|
||||||
defer stats.DecRequestsInProgress()
|
defer stats.DecRequestsInProgress()
|
||||||
|
|
||||||
ctx := imageRequest.Context()
|
ctx := req.Context()
|
||||||
|
|
||||||
// Verify URL signature and extract image url and processing options
|
// Verify URL signature and extract image url and processing options
|
||||||
imageURL, po, mm, err := h.newRequest(ctx, imageRequest)
|
imageURL, po, mm, err := h.newRequest(ctx, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// if processing options indicate raw image streaming, stream it and return
|
// if processing options indicate raw image streaming, stream it and return
|
||||||
if po.Raw {
|
if po.Raw {
|
||||||
return h.stream.Execute(ctx, imageRequest, imageURL, reqID, po, rw)
|
return h.stream.Execute(ctx, req, imageURL, reqID, po, rw)
|
||||||
}
|
}
|
||||||
|
|
||||||
req := &request{
|
hReq := &request{
|
||||||
handler: h,
|
HandlerContext: h,
|
||||||
imageRequest: imageRequest,
|
|
||||||
reqID: reqID,
|
reqID: reqID,
|
||||||
|
req: req,
|
||||||
rw: rw,
|
rw: rw,
|
||||||
config: h.config,
|
config: h.config,
|
||||||
po: po,
|
po: po,
|
||||||
imageURL: imageURL,
|
imageURL: imageURL,
|
||||||
monitoringMeta: mm,
|
monitoringMeta: mm,
|
||||||
semaphores: h.semaphores,
|
hwr: h.HeaderWriter().NewRequest(),
|
||||||
hwr: h.hw.NewRequest(),
|
|
||||||
idf: h.idf,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return req.execute(ctx)
|
return hReq.execute(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// newRequest extracts image url and processing options from request URL and verifies them
|
// newRequest extracts image url and processing options from request URL and verifies them
|
||||||
func (h *Handler) newRequest(
|
func (h *Handler) newRequest(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
imageRequest *http.Request,
|
req *http.Request,
|
||||||
) (string, *options.ProcessingOptions, monitoring.Meta, error) {
|
) (string, *options.ProcessingOptions, monitoring.Meta, error) {
|
||||||
// let's extract signature and valid request path from a request
|
// let's extract signature and valid request path from a request
|
||||||
path, signature, err := handlers.SplitPathSignature(imageRequest)
|
path, signature, err := handlers.SplitPathSignature(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, nil, err
|
return "", nil, nil, err
|
||||||
}
|
}
|
||||||
@@ -112,7 +109,7 @@ func (h *Handler) newRequest(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// parse image url and processing options
|
// parse image url and processing options
|
||||||
po, imageURL, err := options.ParsePath(path, imageRequest.Header)
|
po, imageURL, err := options.ParsePath(path, req.Header)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, nil, ierrors.Wrap(err, 0, ierrors.WithCategory(handlers.CategoryPathParsing))
|
return "", nil, nil, ierrors.Wrap(err, 0, ierrors.WithCategory(handlers.CategoryPathParsing))
|
||||||
}
|
}
|
||||||
@@ -127,9 +124,9 @@ func (h *Handler) newRequest(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// set error reporting and monitoring context
|
// set error reporting and monitoring context
|
||||||
errorreport.SetMetadata(imageRequest, "Source Image URL", imageURL)
|
errorreport.SetMetadata(req, "Source Image URL", imageURL)
|
||||||
errorreport.SetMetadata(imageRequest, "Source Image Origin", imageOrigin)
|
errorreport.SetMetadata(req, "Source Image Origin", imageOrigin)
|
||||||
errorreport.SetMetadata(imageRequest, "Processing Options", po)
|
errorreport.SetMetadata(req, "Processing Options", po)
|
||||||
|
|
||||||
monitoring.SetMetadata(ctx, mm)
|
monitoring.SetMetadata(ctx, mm)
|
||||||
|
|
||||||
|
@@ -9,29 +9,26 @@ import (
|
|||||||
"github.com/imgproxy/imgproxy/v3/handlers"
|
"github.com/imgproxy/imgproxy/v3/handlers"
|
||||||
"github.com/imgproxy/imgproxy/v3/headerwriter"
|
"github.com/imgproxy/imgproxy/v3/headerwriter"
|
||||||
"github.com/imgproxy/imgproxy/v3/ierrors"
|
"github.com/imgproxy/imgproxy/v3/ierrors"
|
||||||
"github.com/imgproxy/imgproxy/v3/imagedata"
|
|
||||||
"github.com/imgproxy/imgproxy/v3/imagetype"
|
"github.com/imgproxy/imgproxy/v3/imagetype"
|
||||||
"github.com/imgproxy/imgproxy/v3/monitoring"
|
"github.com/imgproxy/imgproxy/v3/monitoring"
|
||||||
"github.com/imgproxy/imgproxy/v3/monitoring/stats"
|
"github.com/imgproxy/imgproxy/v3/monitoring/stats"
|
||||||
"github.com/imgproxy/imgproxy/v3/options"
|
"github.com/imgproxy/imgproxy/v3/options"
|
||||||
"github.com/imgproxy/imgproxy/v3/semaphores"
|
|
||||||
"github.com/imgproxy/imgproxy/v3/server"
|
"github.com/imgproxy/imgproxy/v3/server"
|
||||||
"github.com/imgproxy/imgproxy/v3/vips"
|
"github.com/imgproxy/imgproxy/v3/vips"
|
||||||
)
|
)
|
||||||
|
|
||||||
// request holds the parameters and state for a single request request
|
// request holds the parameters and state for a single request request
|
||||||
type request struct {
|
type request struct {
|
||||||
handler *Handler
|
HandlerContext
|
||||||
imageRequest *http.Request
|
|
||||||
reqID string
|
reqID string
|
||||||
|
req *http.Request
|
||||||
rw http.ResponseWriter
|
rw http.ResponseWriter
|
||||||
config *Config
|
config *Config
|
||||||
po *options.ProcessingOptions
|
po *options.ProcessingOptions
|
||||||
imageURL string
|
imageURL string
|
||||||
monitoringMeta monitoring.Meta
|
monitoringMeta monitoring.Meta
|
||||||
semaphores *semaphores.Semaphores
|
|
||||||
hwr *headerwriter.Request
|
hwr *headerwriter.Request
|
||||||
idf *imagedata.Factory
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// execute handles the actual processing logic
|
// execute handles the actual processing logic
|
||||||
@@ -46,7 +43,7 @@ func (r *request) execute(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Acquire queue semaphore (if enabled)
|
// Acquire queue semaphore (if enabled)
|
||||||
releaseQueueSem, err := r.semaphores.AcquireQueue()
|
releaseQueueSem, err := r.Semaphores().AcquireQueue()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@@ -25,12 +25,12 @@ func (r *request) makeImageRequestHeaders() http.Header {
|
|||||||
|
|
||||||
// If ETag is enabled, we forward If-None-Match header
|
// If ETag is enabled, we forward If-None-Match header
|
||||||
if r.config.ETagEnabled {
|
if r.config.ETagEnabled {
|
||||||
h.Set(httpheaders.IfNoneMatch, r.imageRequest.Header.Get(httpheaders.IfNoneMatch))
|
h.Set(httpheaders.IfNoneMatch, r.req.Header.Get(httpheaders.IfNoneMatch))
|
||||||
}
|
}
|
||||||
|
|
||||||
// If LastModified is enabled, we forward If-Modified-Since header
|
// If LastModified is enabled, we forward If-Modified-Since header
|
||||||
if r.config.LastModifiedEnabled {
|
if r.config.LastModifiedEnabled {
|
||||||
h.Set(httpheaders.IfModifiedSince, r.imageRequest.Header.Get(httpheaders.IfModifiedSince))
|
h.Set(httpheaders.IfModifiedSince, r.req.Header.Get(httpheaders.IfModifiedSince))
|
||||||
}
|
}
|
||||||
|
|
||||||
return h
|
return h
|
||||||
@@ -40,7 +40,7 @@ func (r *request) makeImageRequestHeaders() http.Header {
|
|||||||
func (r *request) acquireProcessingSem(ctx context.Context) (context.CancelFunc, error) {
|
func (r *request) acquireProcessingSem(ctx context.Context) (context.CancelFunc, error) {
|
||||||
defer monitoring.StartQueueSegment(ctx)()
|
defer monitoring.StartQueueSegment(ctx)()
|
||||||
|
|
||||||
fn, err := r.semaphores.AcquireProcessing(ctx)
|
fn, err := r.Semaphores().AcquireProcessing(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// We don't actually need to check timeout here,
|
// We don't actually need to check timeout here,
|
||||||
// but it's an easy way to check if this is an actual timeout
|
// but it's an easy way to check if this is an actual timeout
|
||||||
@@ -76,13 +76,13 @@ func (r *request) fetchImage(ctx context.Context, do imagedata.DownloadOptions)
|
|||||||
var err error
|
var err error
|
||||||
|
|
||||||
if r.config.CookiePassthrough {
|
if r.config.CookiePassthrough {
|
||||||
do.CookieJar, err = cookies.JarFromRequest(r.imageRequest)
|
do.CookieJar, err = cookies.JarFromRequest(r.req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, ierrors.Wrap(err, 0, ierrors.WithCategory(handlers.CategoryDownload))
|
return nil, nil, ierrors.Wrap(err, 0, ierrors.WithCategory(handlers.CategoryDownload))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return r.idf.DownloadAsync(ctx, r.imageURL, "source image", do)
|
return r.ImageDataFactory().DownloadAsync(ctx, r.imageURL, "source image", do)
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleDownloadError replaces the image data with fallback image if needed
|
// handleDownloadError replaces the image data with fallback image if needed
|
||||||
@@ -103,7 +103,7 @@ func (r *request) handleDownloadError(
|
|||||||
|
|
||||||
// We didn't return, so we have to report error
|
// We didn't return, so we have to report error
|
||||||
if err.ShouldReport() {
|
if err.ShouldReport() {
|
||||||
errorreport.Report(err, r.imageRequest)
|
errorreport.Report(err, r.req)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.
|
log.
|
||||||
@@ -134,16 +134,18 @@ func (r *request) getFallbackImage(
|
|||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
po *options.ProcessingOptions,
|
po *options.ProcessingOptions,
|
||||||
) (imagedata.ImageData, http.Header) {
|
) (imagedata.ImageData, http.Header) {
|
||||||
if r.handler.fallbackImage == nil {
|
fbi := r.FallbackImage()
|
||||||
|
|
||||||
|
if fbi == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
data, h, err := r.handler.fallbackImage.Get(ctx, po)
|
data, h, err := fbi.Get(ctx, po)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warning(err.Error())
|
log.Warning(err.Error())
|
||||||
|
|
||||||
if ierr := r.wrapDownloadingErr(err); ierr.ShouldReport() {
|
if ierr := r.wrapDownloadingErr(err); ierr.ShouldReport() {
|
||||||
errorreport.Report(ierr, r.imageRequest)
|
errorreport.Report(ierr, r.req)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
@@ -155,7 +157,7 @@ func (r *request) getFallbackImage(
|
|||||||
// processImage calls actual image processing
|
// processImage calls actual image processing
|
||||||
func (r *request) processImage(ctx context.Context, originData imagedata.ImageData) (*processing.Result, error) {
|
func (r *request) processImage(ctx context.Context, originData imagedata.ImageData) (*processing.Result, error) {
|
||||||
defer monitoring.StartProcessingSegment(ctx, r.monitoringMeta.Filter(monitoring.MetaProcessingOptions))()
|
defer monitoring.StartProcessingSegment(ctx, r.monitoringMeta.Filter(monitoring.MetaProcessingOptions))()
|
||||||
return processing.ProcessImage(ctx, originData, r.po, r.handler.watermarkImage)
|
return processing.ProcessImage(ctx, originData, r.po, r.WatermarkImage())
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeDebugHeaders writes debug headers (X-Origin-*, X-Result-*) to the response
|
// writeDebugHeaders writes debug headers (X-Origin-*, X-Result-*) to the response
|
||||||
@@ -200,7 +202,7 @@ func (r *request) respondWithNotModified() error {
|
|||||||
r.rw.WriteHeader(http.StatusNotModified)
|
r.rw.WriteHeader(http.StatusNotModified)
|
||||||
|
|
||||||
server.LogResponse(
|
server.LogResponse(
|
||||||
r.reqID, r.imageRequest, http.StatusNotModified, nil,
|
r.reqID, r.req, http.StatusNotModified, nil,
|
||||||
log.Fields{
|
log.Fields{
|
||||||
"image_url": r.imageURL,
|
"image_url": r.imageURL,
|
||||||
"processing_options": r.po,
|
"processing_options": r.po,
|
||||||
@@ -256,7 +258,7 @@ func (r *request) respondWithImage(statusCode int, resultData imagedata.ImageDat
|
|||||||
}
|
}
|
||||||
|
|
||||||
server.LogResponse(
|
server.LogResponse(
|
||||||
r.reqID, r.imageRequest, statusCode, ierr,
|
r.reqID, r.req, statusCode, ierr,
|
||||||
log.Fields{
|
log.Fields{
|
||||||
"image_url": r.imageURL,
|
"image_url": r.imageURL,
|
||||||
"processing_options": r.po,
|
"processing_options": r.po,
|
||||||
|
78
imgproxy.go
78
imgproxy.go
@@ -34,14 +34,14 @@ type ImgproxyHandlers struct {
|
|||||||
|
|
||||||
// Imgproxy holds all the components needed for imgproxy to function
|
// Imgproxy holds all the components needed for imgproxy to function
|
||||||
type Imgproxy struct {
|
type Imgproxy struct {
|
||||||
HeaderWriter *headerwriter.Writer
|
headerWriter *headerwriter.Writer
|
||||||
Semaphores *semaphores.Semaphores
|
semaphores *semaphores.Semaphores
|
||||||
FallbackImage auximageprovider.Provider
|
fallbackImage auximageprovider.Provider
|
||||||
WatermarkImage auximageprovider.Provider
|
watermarkImage auximageprovider.Provider
|
||||||
Fetcher *fetcher.Fetcher
|
fetcher *fetcher.Fetcher
|
||||||
ImageDataFactory *imagedata.Factory
|
imageDataFactory *imagedata.Factory
|
||||||
Handlers ImgproxyHandlers
|
handlers ImgproxyHandlers
|
||||||
Config *Config
|
config *Config
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new imgproxy instance
|
// New creates a new imgproxy instance
|
||||||
@@ -74,25 +74,25 @@ func New(ctx context.Context, config *Config) (*Imgproxy, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
imgproxy := &Imgproxy{
|
imgproxy := &Imgproxy{
|
||||||
HeaderWriter: headerWriter,
|
headerWriter: headerWriter,
|
||||||
Semaphores: semaphores,
|
semaphores: semaphores,
|
||||||
FallbackImage: fallbackImage,
|
fallbackImage: fallbackImage,
|
||||||
WatermarkImage: watermarkImage,
|
watermarkImage: watermarkImage,
|
||||||
Fetcher: fetcher,
|
fetcher: fetcher,
|
||||||
ImageDataFactory: idf,
|
imageDataFactory: idf,
|
||||||
Config: config,
|
config: config,
|
||||||
}
|
}
|
||||||
|
|
||||||
imgproxy.Handlers.Health = healthhandler.New()
|
imgproxy.handlers.Health = healthhandler.New()
|
||||||
imgproxy.Handlers.Landing = landinghandler.New()
|
imgproxy.handlers.Landing = landinghandler.New()
|
||||||
|
|
||||||
imgproxy.Handlers.Stream, err = streamhandler.New(&config.Handlers.Stream, headerWriter, fetcher)
|
imgproxy.handlers.Stream, err = streamhandler.New(&config.Handlers.Stream, headerWriter, fetcher)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
imgproxy.Handlers.Processing, err = processinghandler.New(
|
imgproxy.handlers.Processing, err = processinghandler.New(
|
||||||
imgproxy.Handlers.Stream, headerWriter, semaphores, fallbackImage, watermarkImage, idf, &config.Handlers.Processing,
|
imgproxy, imgproxy.handlers.Stream, &config.Handlers.Processing,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -103,22 +103,22 @@ func New(ctx context.Context, config *Config) (*Imgproxy, error) {
|
|||||||
|
|
||||||
// BuildRouter sets up the HTTP routes and middleware
|
// BuildRouter sets up the HTTP routes and middleware
|
||||||
func (i *Imgproxy) BuildRouter() (*server.Router, error) {
|
func (i *Imgproxy) BuildRouter() (*server.Router, error) {
|
||||||
r, err := server.NewRouter(&i.Config.Server)
|
r, err := server.NewRouter(&i.config.Server)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
r.GET("/", i.Handlers.Landing.Execute)
|
r.GET("/", i.handlers.Landing.Execute)
|
||||||
r.GET("", i.Handlers.Landing.Execute)
|
r.GET("", i.handlers.Landing.Execute)
|
||||||
|
|
||||||
r.GET(faviconPath, r.NotFoundHandler).Silent()
|
r.GET(faviconPath, r.NotFoundHandler).Silent()
|
||||||
r.GET(healthPath, i.Handlers.Health.Execute).Silent()
|
r.GET(healthPath, i.handlers.Health.Execute).Silent()
|
||||||
if i.Config.Server.HealthCheckPath != "" {
|
if i.config.Server.HealthCheckPath != "" {
|
||||||
r.GET(i.Config.Server.HealthCheckPath, i.Handlers.Health.Execute).Silent()
|
r.GET(i.config.Server.HealthCheckPath, i.handlers.Health.Execute).Silent()
|
||||||
}
|
}
|
||||||
|
|
||||||
r.GET(
|
r.GET(
|
||||||
"/*", i.Handlers.Processing.Execute,
|
"/*", i.handlers.Processing.Execute,
|
||||||
r.WithSecret, r.WithCORS, r.WithPanic, r.WithReportError, r.WithMonitoring,
|
r.WithSecret, r.WithCORS, r.WithPanic, r.WithReportError, r.WithMonitoring,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -163,7 +163,7 @@ func (i *Imgproxy) StartServer(ctx context.Context, hasStarted chan net.Addr) er
|
|||||||
|
|
||||||
// startMemoryTicker starts a ticker that periodically frees memory and optionally logs memory stats
|
// startMemoryTicker starts a ticker that periodically frees memory and optionally logs memory stats
|
||||||
func (i *Imgproxy) startMemoryTicker(ctx context.Context) {
|
func (i *Imgproxy) startMemoryTicker(ctx context.Context) {
|
||||||
ticker := time.NewTicker(i.Config.Server.FreeMemoryInterval)
|
ticker := time.NewTicker(i.config.Server.FreeMemoryInterval)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
@@ -173,9 +173,29 @@ func (i *Imgproxy) startMemoryTicker(ctx context.Context) {
|
|||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
memory.Free()
|
memory.Free()
|
||||||
|
|
||||||
if i.Config.Server.LogMemStats {
|
if i.config.Server.LogMemStats {
|
||||||
memory.LogStats()
|
memory.LogStats()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *Imgproxy) HeaderWriter() *headerwriter.Writer {
|
||||||
|
return i.headerWriter
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Imgproxy) Semaphores() *semaphores.Semaphores {
|
||||||
|
return i.semaphores
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Imgproxy) FallbackImage() auximageprovider.Provider {
|
||||||
|
return i.fallbackImage
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Imgproxy) WatermarkImage() auximageprovider.Provider {
|
||||||
|
return i.watermarkImage
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Imgproxy) ImageDataFactory() *imagedata.Factory {
|
||||||
|
return i.imageDataFactory
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user