mirror of
https://github.com/lovell/sharp.git
synced 2025-07-09 18:40:16 +02:00
Add timeout function to limit processing time
This commit is contained in:
parent
197d4cf835
commit
1dd4be670d
@ -542,6 +542,26 @@ sharp('input.tiff')
|
|||||||
|
|
||||||
Returns **Sharp**
|
Returns **Sharp**
|
||||||
|
|
||||||
|
## timeout
|
||||||
|
|
||||||
|
Set a timeout for processing, in seconds.
|
||||||
|
Use a value of zero to continue processing indefinitely, the default behaviour.
|
||||||
|
|
||||||
|
The clock starts when libvips opens an input image for processing.
|
||||||
|
Time spent waiting for a libuv thread to become available is not included.
|
||||||
|
|
||||||
|
### Parameters
|
||||||
|
|
||||||
|
* `options` **[Object][6]**
|
||||||
|
|
||||||
|
* `options.seconds` **[number][9]** Number of seconds after which processing will be stopped
|
||||||
|
|
||||||
|
Returns **Sharp**
|
||||||
|
|
||||||
|
**Meta**
|
||||||
|
|
||||||
|
* **since**: 0.29.2
|
||||||
|
|
||||||
[1]: #withmetadata
|
[1]: #withmetadata
|
||||||
|
|
||||||
[2]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String
|
[2]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String
|
||||||
|
@ -6,6 +6,8 @@ Requires libvips v8.11.3
|
|||||||
|
|
||||||
### v0.29.2 - TBD
|
### v0.29.2 - TBD
|
||||||
|
|
||||||
|
* Add `timeout` function to limit processing time.
|
||||||
|
|
||||||
* Ensure `sharp.versions` is populated from vendored libvips.
|
* Ensure `sharp.versions` is populated from vendored libvips.
|
||||||
|
|
||||||
* Allow use of 'tif' to select TIFF output.
|
* Allow use of 'tif' to select TIFF output.
|
||||||
|
File diff suppressed because one or more lines are too long
@ -273,6 +273,7 @@ const Sharp = function (input, options) {
|
|||||||
tileBackground: [255, 255, 255, 255],
|
tileBackground: [255, 255, 255, 255],
|
||||||
tileCentre: false,
|
tileCentre: false,
|
||||||
tileId: 'https://example.com/iiif',
|
tileId: 'https://example.com/iiif',
|
||||||
|
timeoutSeconds: 0,
|
||||||
linearA: 1,
|
linearA: 1,
|
||||||
linearB: 0,
|
linearB: 0,
|
||||||
// Function to notify of libvips warnings
|
// Function to notify of libvips warnings
|
||||||
|
@ -975,6 +975,31 @@ function tile (options) {
|
|||||||
return this._updateFormatOut('dz');
|
return this._updateFormatOut('dz');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a timeout for processing, in seconds.
|
||||||
|
* Use a value of zero to continue processing indefinitely, the default behaviour.
|
||||||
|
*
|
||||||
|
* The clock starts when libvips opens an input image for processing.
|
||||||
|
* Time spent waiting for a libuv thread to become available is not included.
|
||||||
|
*
|
||||||
|
* @since 0.29.2
|
||||||
|
*
|
||||||
|
* @param {Object} options
|
||||||
|
* @param {number} options.seconds - Number of seconds after which processing will be stopped
|
||||||
|
* @returns {Sharp}
|
||||||
|
*/
|
||||||
|
function timeout (options) {
|
||||||
|
if (!is.plainObject(options)) {
|
||||||
|
throw is.invalidParameterError('options', 'object', options);
|
||||||
|
}
|
||||||
|
if (is.integer(options.seconds) && is.inRange(options.seconds, 0, 3600)) {
|
||||||
|
this.options.timeoutSeconds = options.seconds;
|
||||||
|
} else {
|
||||||
|
throw is.invalidParameterError('seconds', 'integer between 0 and 3600', options.seconds);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the output format unless options.force is false,
|
* Update the output format unless options.force is false,
|
||||||
* in which case revert to input format.
|
* in which case revert to input format.
|
||||||
@ -1129,6 +1154,7 @@ module.exports = function (Sharp) {
|
|||||||
gif,
|
gif,
|
||||||
raw,
|
raw,
|
||||||
tile,
|
tile,
|
||||||
|
timeout,
|
||||||
// Private
|
// Private
|
||||||
_updateFormatOut,
|
_updateFormatOut,
|
||||||
_setBooleanOption,
|
_setBooleanOption,
|
||||||
|
@ -610,6 +610,33 @@ namespace sharp {
|
|||||||
return warning;
|
return warning;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Attach an event listener for progress updates, used to detect timeout
|
||||||
|
*/
|
||||||
|
void SetTimeout(VImage image, int const seconds) {
|
||||||
|
if (seconds > 0) {
|
||||||
|
VipsImage *im = image.get_image();
|
||||||
|
if (im->progress_signal == NULL) {
|
||||||
|
int *timeout = VIPS_NEW(im, int);
|
||||||
|
*timeout = seconds;
|
||||||
|
g_signal_connect(im, "eval", G_CALLBACK(VipsProgressCallBack), timeout);
|
||||||
|
vips_image_set_progress(im, TRUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Event listener for progress updates, used to detect timeout
|
||||||
|
*/
|
||||||
|
void VipsProgressCallBack(VipsImage *im, VipsProgress *progress, int *timeout) {
|
||||||
|
// printf("VipsProgressCallBack progress=%d run=%d timeout=%d\n", progress->percent, progress->run, *timeout);
|
||||||
|
if (*timeout > 0 && progress->run >= *timeout) {
|
||||||
|
vips_image_set_kill(im, TRUE);
|
||||||
|
vips_error("timeout", "%d%% complete", progress->percent);
|
||||||
|
*timeout = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Calculate the (left, top) coordinates of the output image
|
Calculate the (left, top) coordinates of the output image
|
||||||
within the input image, applying the given gravity during an embed.
|
within the input image, applying the given gravity during an embed.
|
||||||
|
10
src/common.h
10
src/common.h
@ -250,6 +250,16 @@ namespace sharp {
|
|||||||
*/
|
*/
|
||||||
std::string VipsWarningPop();
|
std::string VipsWarningPop();
|
||||||
|
|
||||||
|
/*
|
||||||
|
Attach an event listener for progress updates, used to detect timeout
|
||||||
|
*/
|
||||||
|
void SetTimeout(VImage image, int const timeoutSeconds);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Event listener for progress updates, used to detect timeout
|
||||||
|
*/
|
||||||
|
void VipsProgressCallBack(VipsImage *image, VipsProgress *progress, int *timeoutSeconds);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Calculate the (left, top) coordinates of the output image
|
Calculate the (left, top) coordinates of the output image
|
||||||
within the input image, applying the given gravity during an embed.
|
within the input image, applying the given gravity during an embed.
|
||||||
|
@ -764,6 +764,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
baton->loop);
|
baton->loop);
|
||||||
|
|
||||||
// Output
|
// Output
|
||||||
|
sharp::SetTimeout(image, baton->timeoutSeconds);
|
||||||
if (baton->fileOut.empty()) {
|
if (baton->fileOut.empty()) {
|
||||||
// Buffer output
|
// Buffer output
|
||||||
if (baton->formatOut == "jpeg" || (baton->formatOut == "input" && inputImageType == sharp::ImageType::JPEG)) {
|
if (baton->formatOut == "jpeg" || (baton->formatOut == "input" && inputImageType == sharp::ImageType::JPEG)) {
|
||||||
@ -1451,6 +1452,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|||||||
std::string k = sharp::AttrAsStr(mdStrKeys, i);
|
std::string k = sharp::AttrAsStr(mdStrKeys, i);
|
||||||
baton->withMetadataStrs.insert(std::make_pair(k, sharp::AttrAsStr(mdStrs, k)));
|
baton->withMetadataStrs.insert(std::make_pair(k, sharp::AttrAsStr(mdStrs, k)));
|
||||||
}
|
}
|
||||||
|
baton->timeoutSeconds = sharp::AttrAsUint32(options, "timeoutSeconds");
|
||||||
// Format-specific
|
// Format-specific
|
||||||
baton->jpegQuality = sharp::AttrAsUint32(options, "jpegQuality");
|
baton->jpegQuality = sharp::AttrAsUint32(options, "jpegQuality");
|
||||||
baton->jpegProgressive = sharp::AttrAsBool(options, "jpegProgressive");
|
baton->jpegProgressive = sharp::AttrAsBool(options, "jpegProgressive");
|
||||||
|
@ -182,6 +182,7 @@ struct PipelineBaton {
|
|||||||
double withMetadataDensity;
|
double withMetadataDensity;
|
||||||
std::string withMetadataIcc;
|
std::string withMetadataIcc;
|
||||||
std::unordered_map<std::string, std::string> withMetadataStrs;
|
std::unordered_map<std::string, std::string> withMetadataStrs;
|
||||||
|
int timeoutSeconds;
|
||||||
std::unique_ptr<double[]> convKernel;
|
std::unique_ptr<double[]> convKernel;
|
||||||
int convKernelWidth;
|
int convKernelWidth;
|
||||||
int convKernelHeight;
|
int convKernelHeight;
|
||||||
@ -315,6 +316,7 @@ struct PipelineBaton {
|
|||||||
withMetadata(false),
|
withMetadata(false),
|
||||||
withMetadataOrientation(-1),
|
withMetadataOrientation(-1),
|
||||||
withMetadataDensity(0.0),
|
withMetadataDensity(0.0),
|
||||||
|
timeoutSeconds(0),
|
||||||
convKernelWidth(0),
|
convKernelWidth(0),
|
||||||
convKernelHeight(0),
|
convKernelHeight(0),
|
||||||
convKernelScale(0.0),
|
convKernelScale(0.0),
|
||||||
|
26
test/unit/timeout.js
Normal file
26
test/unit/timeout.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const assert = require('assert');
|
||||||
|
|
||||||
|
const sharp = require('../../');
|
||||||
|
const fixtures = require('../fixtures');
|
||||||
|
|
||||||
|
describe('Timeout', function () {
|
||||||
|
it('Will timeout after 1s when performing slow blur operation', () => assert.rejects(
|
||||||
|
() => sharp(fixtures.inputJpg)
|
||||||
|
.blur(100)
|
||||||
|
.timeout({ seconds: 1 })
|
||||||
|
.toBuffer(),
|
||||||
|
/timeout: [0-9]+% complete/
|
||||||
|
));
|
||||||
|
|
||||||
|
it('invalid object', () => assert.throws(
|
||||||
|
() => sharp().timeout('fail'),
|
||||||
|
/Expected object for options but received fail of type string/
|
||||||
|
));
|
||||||
|
|
||||||
|
it('invalid seconds', () => assert.throws(
|
||||||
|
() => sharp().timeout({ seconds: 'fail' }),
|
||||||
|
/Expected integer between 0 and 3600 for seconds but received fail of type string/
|
||||||
|
));
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user