Fixed Non-ASCII attachment filename will crash when downloading.

Thanks to xet7 !

Fixes #2759
This commit is contained in:
Lauri Ojansivu 2021-04-29 13:26:49 +03:00
parent 843ff8eaaa
commit c2da477735
277 changed files with 30568 additions and 52 deletions

View file

@ -0,0 +1,18 @@
# .editorconfig
# Meteor adapted EditorConfig, http://EditorConfig.org
# By RaiX 2013
root = true
[*.js]
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
charset = utf-8
max_line_length = 80
indent_brace_style = 1TBS
spaces_around_operators = true
quote_type = auto
# curly_bracket_next_line = true

View file

@ -0,0 +1,3 @@
/versions.json
/nbproject/private/
.build*

View file

@ -0,0 +1,114 @@
//.jshintrc
{
// JSHint Meteor Configuration File
// Match the Meteor Style Guide
//
// By @raix with contributions from @aldeed and @awatson1978
// Source https://github.com/raix/Meteor-jshintrc
//
// See http://jshint.com/docs/ for more details
"maxerr" : 50, // {int} Maximum error before stopping
// Enforcing
"bitwise" : true, // true: Prohibit bitwise operators (&, |, ^, etc.)
"camelcase" : true, // true: Identifiers must be in camelCase
"curly" : true, // true: Require {} for every new block or scope
"eqeqeq" : true, // true: Require triple equals (===) for comparison
"forin" : true, // true: Require filtering for..in loops with obj.hasOwnProperty()
"immed" : false, // true: Require immediate invocations to be wrapped in parens e.g. `(function () { } ());`
"indent" : 2, // {int} Number of spaces to use for indentation
"latedef" : false, // true: Require variables/functions to be defined before being used
"newcap" : false, // true: Require capitalization of all constructor functions e.g. `new F()`
"noarg" : true, // true: Prohibit use of `arguments.caller` and `arguments.callee`
"noempty" : true, // true: Prohibit use of empty blocks
"nonew" : false, // true: Prohibit use of constructors for side-effects (without assignment)
"plusplus" : false, // true: Prohibit use of `++` & `--`
"quotmark" : false, // Quotation mark consistency:
// false : do nothing (default)
// true : ensure whatever is used is consistent
// "single" : require single quotes
// "double" : require double quotes
"undef" : true, // true: Require all non-global variables to be declared (prevents global leaks)
"unused" : true, // true: Require all defined variables be used
"strict" : true, // true: Requires all functions run in ES5 Strict Mode
"trailing" : true, // true: Prohibit trailing whitespaces
"maxparams" : false, // {int} Max number of formal params allowed per function
"maxdepth" : false, // {int} Max depth of nested blocks (within functions)
"maxstatements" : false, // {int} Max number statements per function
"maxcomplexity" : false, // {int} Max cyclomatic complexity per function
"maxlen" : 80, // {int} Max number of characters per line
// Relaxing
"asi" : false, // true: Tolerate Automatic Semicolon Insertion (no semicolons)
"boss" : false, // true: Tolerate assignments where comparisons would be expected
"debug" : false, // true: Allow debugger statements e.g. browser breakpoints.
"eqnull" : false, // true: Tolerate use of `== null`
"es5" : false, // true: Allow ES5 syntax (ex: getters and setters)
"esnext" : false, // true: Allow ES.next (ES6) syntax (ex: `const`)
"moz" : false, // true: Allow Mozilla specific syntax (extends and overrides esnext features)
// (ex: `for each`, multiple try/catch, function expression…)
"evil" : false, // true: Tolerate use of `eval` and `new Function()`
"expr" : false, // true: Tolerate `ExpressionStatement` as Programs
"funcscope" : false, // true: Tolerate defining variables inside control statements"
"globalstrict" : true, // true: Allow global "use strict" (also enables 'strict')
"iterator" : false, // true: Tolerate using the `__iterator__` property
"lastsemic" : false, // true: Tolerate omitting a semicolon for the last statement of a 1-line block
"laxbreak" : false, // true: Tolerate possibly unsafe line breakings
"laxcomma" : false, // true: Tolerate comma-first style coding
"loopfunc" : false, // true: Tolerate functions being defined in loops
"multistr" : false, // true: Tolerate multi-line strings
"proto" : false, // true: Tolerate using the `__proto__` property
"scripturl" : false, // true: Tolerate script-targeted URLs
"smarttabs" : false, // true: Tolerate mixed tabs/spaces when used for alignment
"shadow" : false, // true: Allows re-define variables later in code e.g. `var x=1; x=2;`
"sub" : false, // true: Tolerate using `[]` notation when it can still be expressed in dot notation
"supernew" : false, // true: Tolerate `new function () { ... };` and `new Object;`
"validthis" : false, // true: Tolerate using this in a non-constructor function
// Environments
"browser" : true, // Web Browser (window, document, etc)
"couch" : false, // CouchDB
"devel" : true, // Development/debugging (alert, confirm, etc)
"dojo" : false, // Dojo Toolkit
"jquery" : false, // jQuery
"mootools" : false, // MooTools
"node" : false, // Node.js
"nonstandard" : false, // Widely adopted globals (escape, unescape, etc)
"prototypejs" : false, // Prototype and Scriptaculous
"rhino" : false, // Rhino
"worker" : false, // Web Workers
"wsh" : false, // Windows Scripting Host
"yui" : false, // Yahoo User Interface
//"meteor" : false, // Meteor.js
// Legacy
"nomen" : false, // true: Prohibit dangling `_` in variables
"onevar" : false, // true: Allow only one `var` statement per function
"passfail" : false, // true: Stop on first error
"white" : false, // true: Check against strict whitespace and indentation rules
// Custom Globals
"predef" : [
"Meteor",
"Accounts",
"Session",
"Template",
"check",
"Match",
"Deps",
"EJSON",
"Email",
"Package",
"Tinytest",
"Npm",
"Assets",
"Packages",
"process",
"GroundDB",
"_gDB",
"LocalCollection",
"_",
"Random"
] // additional predefined global variables
}

View file

@ -0,0 +1,5 @@
language: node_js
node_js:
- "0.10"
before_install:
- "curl -L http://git.io/s0Zu-w | /bin/sh"

View file

@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2013 [@raix](https://github.com/raix), aka Morten N.O. Nørgaard Henriksen, mh@gi-software.com
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -0,0 +1,136 @@
wekan-cfs-power-queue [![Build Status](https://travis-ci.org/CollectionFS/Meteor-powerqueue.png?branch=master)](https://travis-ci.org/CollectionFS/Meteor-powerqueue)
=========
~~Looking for maintainers - please reach out!~~
This package is to be archived due to inability to find contributors, thanks to everyone who helped make it possible.
**If you're looking for an alternative, we highly recommend [Meteor-Files](https://github.com/VeliovGroup/Meteor-Files) by [VeliovGroup](https://github.com/VeliovGroup)**
---
PowerQueue is a native Meteor package for memory-backed job queue processing. Features include:
* async tasks
* throttling resource usage
* retrying failed tasks
* managing sub-queues
* powered by Meteor's reactive sugar
* etc.
PowerQueue can use one of two [spinal-queue](https://github.com/zcfs/Meteor-power-queue/blob/master/spinal-queue.spec.md) packages, [ReactiveList](https://github.com/zcfs/Meteor-reactive-list) or [MicroQueue](https://github.com/zcfs/Meteor-micro-queue).
## Demos
**Check out the cool [live queue demo](http://power-queue-test.meteor.com) and [live sub queue example](http://power-queue-sub-test.meteor.com).**
Source code for both can be found in the two branches of the [power-queue-example repo](https://github.com/zcfs/power-queue-example).
Kind regards,
Eric(@aldeed) and Morten(@raix)
Happy coding!
# API
All getters and setters are reactive.
[API Documentation](api.md)
## Helpers / Getters / Setters:
* PowerQueue.length - Number of tasks in queue
* PowerQueue.progress - Current progress in percent
* PowerQueue.usage - Current load in percent
* PowerQueue.total - Sum of tasks to run in current queue
* PowerQueue.isPaused - True if queue is paused
* PowerQueue.isHalted - True if queue is paused or stopped
* PowerQueue.processing - Number of tasks being processed
* PowerQueue.errors - Failures where task is passed to the errorHandler
* PowerQueue.failures - Number of failures in current queue
* PowerQueue.isRunning - True if queue is active
* PowerQueue.maxProcessing - Getter + Setter for max tasks to run in parallel
* PowerQueue.autostart - Getter + Setter for autostart flag - Allow add task to start the queue
* PowerQueue.maxFailures - Max allowed retries for failing tasks before marked as an error
* options.queue - Use custom micro-queue compatible queue
* options.onEnded - Called when queue has ended
* options.onRelease(remainingTasks) - Called when queue has ended or paused
* options.onAutostart - Called when queue was autostarted
## Methods
* PowerQueue.add(data) - Add a task to queue
* PowerQueue.run() - Start the queue
* PowerQueue.pause() - Pause the queue
* PowerQueue.resume() - Resume the queue if paused
* PowerQueue.reset() - Reset the queue
* PowerQueue.taskHandler(data, next, failures) - Default task handler, where data is a `function(done)`, can be overwritten
* PowerQueue.errorHandler(data, addTask, failures) - Default error handler, can be overwritten
# Example 1
```js
var queue = new PowerQueue({
isPaused: true
});
queue.add(function(done) {
console.log('task 1');
done();
});
queue.add(function(done) {
console.log('task 2');
done();
});
queue.add(function(done) {
console.log('task 3');
done();
});
console.log('Ready to run queue');
queue.run();
```
# Example 2
This is a very rough example of how to make custom task handling.
```js
queue.errorHandler = function(data, addTask) {
// This error handler lets the task drop, but we could use addTask to
// Put the task into the queue again
tasks.update({ _id: data.id }, { $set: { status: 'error'} });
};
queue.taskHandler = function(data, next) {
// The task is now processed...
tasks.update({ _id: data.id }, { $set: { status: 'processing'} });
Meteor.setTimeout(function() {
if (Math.random() > 0.5) {
// We random fail the task
tasks.update({ _id: data.id }, { $set: { status: 'failed'} });
// Returning error to next
next('Error: Fail task');
} else {
// We are done!
tasks.update({ _id: data.id }, { $set: { status: 'done'} });
// Trigger next task
next();
}
// This async task duration is between 500 - 1000ms
}, Math.round(500 + 500 * Math.random()));
};
// Add the task:
var taskId = 0;
queue.add({ id: tasks.insert({ status: 'added', index: ++taskId }) });
```
# Contribute
Here's the [complete API documentation](internal.api.md), including private methods.
To update the docs, run `npm install docmeteor` then `docmeteor`.
## TODO / Wishlist
* scheduling jobs to run in the future, like [meteor-queue](https://github.com/artwells/meteor-queue#features) - see [issue #15](https://github.com/zcfs/Meteor-power-queue/issues/15)

View file

@ -0,0 +1,420 @@
#### <a name="PowerQueue"></a>new PowerQueue([options])&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
```
Creates an instance of a power queue
[Check out demo](http://power-queue-test.meteor.com/)
```
-
__Arguments__
* __options__ *{object}* (Optional)
Settings
- __filo__ *{boolean}* (Default = false)
Make it a first in last out queue
- __isPaused__ *{boolean}* (Default = false)
Set queue paused
- __autostart__ *{boolean}* (Default = true)
May adding a task start the queue
- __name__ *{string}* (Default = "Queue")
Name of the queue
- __maxProcessing__ *{number}* (Default = 1)
Limit of simultanous running tasks
- __maxFailures__ *{number}* (Default = 5)
Limit retries of failed tasks, if 0 or below we allow infinite failures
- __jumpOnFailure__ *{number}* (Default = true)
Jump to next task and retry failed task later
- __debug__ *{boolean}* (Default = false)
Log verbose messages to the console
- __reactive__ *{boolean}* (Default = true)
Set whether or not this queue should be reactive
- __spinalQueue__ *{[SpinalQueue](spinal-queue.spec.md)}* (Optional)
Set spinal queue uses pr. default `MicroQueue` or `ReactiveList` if added to the project
-
> ```PowerQueue = function(options) { ...``` [power-queue.js:27](power-queue.js#L27)
-
#### <a name="PowerQueue.onEnded"></a>*powerqueue*.onEnded&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This callback __onEnded__ is defined in `PowerQueue`*
Is called when queue is ended
> ```self.onEnded = options && options.onEnded || function() { ...``` [power-queue.js:103](power-queue.js#L103)
-
#### <a name="PowerQueue.onRelease"></a>*powerqueue*.onRelease&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This callback __onRelease__ is defined in `PowerQueue`*
Is called when queue is released
> ```self.onRelease = options && options.onRelease || function() { ...``` [power-queue.js:110](power-queue.js#L110)
-
#### <a name="PowerQueue.onAutostart"></a>*powerqueue*.onAutostart&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This callback __onAutostart__ is defined in `PowerQueue`*
Is called when queue is auto started
> ```self.onAutostart = options && options.onAutostart || function() { ...``` [power-queue.js:115](power-queue.js#L115)
-
#### <a name="PowerQueue.total"></a>*powerqueue*.total()&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __total__ is defined in `PowerQueue`*
__Returns__ *{number}* __(is reactive)__
The total number of tasks added to this queue
> ```self.total = self._maxLength.get;``` [power-queue.js:123](power-queue.js#L123)
-
#### <a name="PowerQueue.isPaused"></a>*powerqueue*.isPaused()&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __isPaused__ is defined in `PowerQueue`*
__Returns__ *{boolean}* __(is reactive)__
Status of the paused state of the queue
> ```self.isPaused = self._paused.get;``` [power-queue.js:129](power-queue.js#L129)
-
#### <a name="PowerQueue.processing"></a>*powerqueue*.processing()&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __processing__ is defined in `PowerQueue`*
__Returns__ *{number}* __(is reactive)__
Number of tasks currently being processed
> ```self.processing = self._isProcessing.get;``` [power-queue.js:135](power-queue.js#L135)
-
#### <a name="PowerQueue.errors"></a>*powerqueue*.errors()&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __errors__ is defined in `PowerQueue`*
__Returns__ *{number}* __(is reactive)__
The total number of errors
Errors are triggered when [maxFailures](PowerQueue.maxFailures) are exeeded
> ```self.errors = self._errors.get;``` [power-queue.js:142](power-queue.js#L142)
-
#### <a name="PowerQueue.failures"></a>*powerqueue*.failures()&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __failures__ is defined in `PowerQueue`*
__Returns__ *{number}* __(is reactive)__
The total number of failed tasks
> ```self.failures = self._failures.get;``` [power-queue.js:148](power-queue.js#L148)
-
#### <a name="PowerQueue.isRunning"></a>*powerqueue*.isRunning()&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __isRunning__ is defined in `PowerQueue`*
__Returns__ *{boolean}* __(is reactive)__
True if the queue is running
> NOTE: The task can be paused but marked as running
> ```self.isRunning = self._running.get;``` [power-queue.js:155](power-queue.js#L155)
-
#### <a name="PowerQueue.maxProcessing"></a>*powerqueue*.maxProcessing([max])&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __maxProcessing__ is defined in `PowerQueue`*
__Arguments__
* __max__ *{number}* (Optional)
If not used this function works as a getter
-
__Returns__ *{number}* __(is reactive)__
Maximum number of simultaneous processing tasks
Example:
```js
foo.maxProcessing(); // Works as a getter and returns the current value
foo.maxProcessing(20); // This sets the value to 20
```
> ```self.maxProcessing = self._maxProcessing.getset;``` [power-queue.js:168](power-queue.js#L168)
-
#### <a name="PowerQueue.autostart"></a>*powerqueue*.autostart([autorun])&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __autostart__ is defined in `PowerQueue`*
__Arguments__
* __autorun__ *{boolean}* (Optional)
If not used this function works as a getter
-
__Returns__ *{boolean}* __(is reactive)__
If adding a task may trigger the queue to start
Example:
```js
foo.autostart(); // Works as a getter and returns the current value
foo.autostart(true); // This sets the value to true
```
> ```self.autostart = self._autostart.getset;``` [power-queue.js:189](power-queue.js#L189)
-
#### <a name="PowerQueue.maxFailures"></a>*powerqueue*.maxFailures([max])&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __maxFailures__ is defined in `PowerQueue`*
__Arguments__
* __max__ *{number}* (Optional)
If not used this function works as a getter
-
__Returns__ *{number}* __(is reactive)__
The maximum for failures pr. task before triggering an error
Example:
```js
foo.maxFailures(); // Works as a getter and returns the current value
foo.maxFailures(10); // This sets the value to 10
```
> ```self.maxFailures = self._maxFailures.getset;``` [power-queue.js:202](power-queue.js#L202)
-
#### <a name="PowerQueue.prototype.processList"></a>*powerqueue*.processList()&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __processList__ is defined in `prototype` of `PowerQueue`*
__Returns__ *{array}* __(is reactive)__
List of tasks currently being processed
> ```PowerQueue.prototype.processingList = function() { ...``` [power-queue.js:209](power-queue.js#L209)
-
#### <a name="PowerQueue.prototype.isHalted"></a>*powerqueue*.isHalted()&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __isHalted__ is defined in `prototype` of `PowerQueue`*
__Returns__ *{boolean}* __(is reactive)__
True if the queue is not running or paused
> ```PowerQueue.prototype.isHalted = function() { ...``` [power-queue.js:218](power-queue.js#L218)
-
#### <a name="PowerQueue.prototype.length"></a>*powerqueue*.length()&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __length__ is defined in `prototype` of `PowerQueue`*
__Returns__ *{number}* __(is reactive)__
Number of tasks left in queue to be processed
> ```PowerQueue.prototype.length = function() { ...``` [power-queue.js:227](power-queue.js#L227)
-
#### <a name="PowerQueue.prototype.progress"></a>*powerqueue*.progress()&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __progress__ is defined in `prototype` of `PowerQueue`*
__Returns__ *{number}* __(is reactive)__
0 .. 100 % Indicates the status of the queue
> ```PowerQueue.prototype.progress = function() { ...``` [power-queue.js:236](power-queue.js#L236)
-
#### <a name="PowerQueue.prototype.usage"></a>*powerqueue*.usage()&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __usage__ is defined in `prototype` of `PowerQueue`*
__Returns__ *{number}* __(is reactive)__
0 .. 100 % Indicates ressource usage of the queue
> ```PowerQueue.prototype.usage = function() { ...``` [power-queue.js:249](power-queue.js#L249)
-
#### <a name="PowerQueue.prototype.reset"></a>*powerqueue*.reset()&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __reset__ is defined in `prototype` of `PowerQueue`*
Calling this will:
* stop the queue
* paused to false
* Discart all queue data
> NOTE: At the moment if the queue has processing tasks they can change
> the `errors` and `failures` counters. This could change in the future or
> be prevented by creating a whole new instance of the `PowerQueue`
> ```PowerQueue.prototype.reset = function() { ...``` [power-queue.js:264](power-queue.js#L264)
-
#### <a name="PowerQueue.prototype.add"></a>*powerqueue*.add(data, [failures])&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __add__ is defined in `prototype` of `PowerQueue`*
__Arguments__
* __data__ *{any}*
The task to be handled
* __failures__ *{number}* (Optional)
Internally used to Pass on number of failures.
-
> ```PowerQueue.prototype.add = function(data, failures, id) { ...``` [power-queue.js:316](power-queue.js#L316)
-
#### <a name="PowerQueue.prototype.next"></a>*powerqueue*.next([err])&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __next__ is defined in `prototype` of `PowerQueue`*
__Arguments__
* __err__ *{string}* (Optional)
Error message if task failed
-
> * Can pass in `null` to start the queue
> * Passing in a string to `next` will trigger a failure
> * Passing nothing will simply let the next task run
`next` is handed into the [taskHandler](PowerQueue.taskHandler) as a
callback to mark an error or end of current task
> ```PowerQueue.prototype.next = function(err) { ...``` [power-queue.js:394](power-queue.js#L394)
-
#### <a name="PowerQueue.prototype.queueTaskHandler"></a>*powerqueue*.queueTaskHandler()&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __queueTaskHandler__ is defined in `prototype` of `PowerQueue`*
This method handles tasks that are sub queues
> ```PowerQueue.prototype.queueTaskHandler = function(subQueue, next, failures) { ...``` [power-queue.js:555](power-queue.js#L555)
-
#### <a name="PowerQueue.prototype.taskHandler"></a>*powerqueue*.taskHandler&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This callback __taskHandler__ is defined in `prototype` of `PowerQueue`*
__Arguments__
* __data__ *{any}*
This can be data or functions
* __next__ *{function}*
Function `next` call this to end task
* __failures__ *{number}*
Number of failures on this task
-
Default task handler expects functions as data:
```js
self.taskHandler = function(data, next, failures) {
// This default task handler expects invocation to be a function to run
if (typeof data !== 'function') {
throw new Error('Default task handler expects a function');
}
try {
// Have the function call next
data(next, failures);
} catch(err) {
// Throw to fail this task
next(err);
}
};
```
> ```PowerQueue.prototype.taskHandler = function(data, next, failures) { ...``` [power-queue.js:601](power-queue.js#L601)
-
#### <a name="PowerQueue.prototype.errorHandler"></a>*powerqueue*.errorHandler&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This callback __errorHandler__ is defined in `prototype` of `PowerQueue`*
__Arguments__
* __data__ *{any}*
This can be data or functions
* __addTask__ *{function}*
Use this function to insert the data into the queue again
* __failures__ *{number}*
Number of failures on this task
-
The default callback:
```js
var foo = new PowerQueue();
// Overwrite the default action
foo.errorHandler = function(data, addTask, failures) {
// This could be overwritten the data contains the task data and addTask
// is a helper for adding the task to the queue
// try again: addTask(data);
// console.log('Terminate at ' + failures + ' failures');
};
```
> ```PowerQueue.prototype.errorHandler = function(data, addTask, failures) { ...``` [power-queue.js:634](power-queue.js#L634)
-
#### <a name="PowerQueue.prototype.pause"></a>*powerqueue*.pause()&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __pause__ is defined in `prototype` of `PowerQueue`*
> ```PowerQueue.prototype.pause = function() { ...``` [power-queue.js:645](power-queue.js#L645)
-
#### <a name="PowerQueue.prototype.resume"></a>*powerqueue*.resume()&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __resume__ is defined in `prototype` of `PowerQueue`*
> This will not start a stopped queue
> ```PowerQueue.prototype.resume = function() { ...``` [power-queue.js:665](power-queue.js#L665)
-
#### <a name="PowerQueue.prototype.run"></a>*powerqueue*.run()&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __run__ is defined in `prototype` of `PowerQueue`*
> Using this command will resume a paused queue and will
> start a stopped queue.
> ```PowerQueue.prototype.run = function() { ...``` [power-queue.js:677](power-queue.js#L677)
-

View file

@ -0,0 +1,535 @@
> File: ["power-queue.js"](power-queue.js)
> Where: {client|server}
-
#### <a name="PowerQueue"></a>new PowerQueue([options])&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
```
Creates an instance of a power queue
[Check out demo](http://power-queue-test.meteor.com/)
```
-
__Arguments__
* __options__ *{object}* (Optional)
Settings
- __filo__ *{boolean}* (Default = false)
Make it a first in last out queue
- __isPaused__ *{boolean}* (Default = false)
Set queue paused
- __autostart__ *{boolean}* (Default = true)
May adding a task start the queue
- __name__ *{string}* (Default = "Queue")
Name of the queue
- __maxProcessing__ *{number}* (Default = 1)
Limit of simultanous running tasks
- __maxFailures__ *{number}* (Default = 5)
Limit retries of failed tasks, if 0 or below we allow infinite failures
- __jumpOnFailure__ *{number}* (Default = true)
Jump to next task and retry failed task later
- __debug__ *{boolean}* (Default = false)
Log verbose messages to the console
- __reactive__ *{boolean}* (Default = true)
Set whether or not this queue should be reactive
- __spinalQueue__ *{[SpinalQueue](spinal-queue.spec.md)}* (Optional)
Set spinal queue uses pr. default `MicroQueue` or `ReactiveList` if added to the project
-
> ```PowerQueue = function(options) { ...``` [power-queue.js:27](power-queue.js#L27)
-
#### <a name="PowerQueue.onEnded"></a>*powerqueue*.onEnded&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This callback __onEnded__ is defined in `PowerQueue`*
Is called when queue is ended
> ```self.onEnded = options && options.onEnded || function() { ...``` [power-queue.js:103](power-queue.js#L103)
-
#### <a name="PowerQueue.onRelease"></a>*powerqueue*.onRelease&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This callback __onRelease__ is defined in `PowerQueue`*
Is called when queue is released
> ```self.onRelease = options && options.onRelease || function() { ...``` [power-queue.js:110](power-queue.js#L110)
-
#### <a name="PowerQueue.onAutostart"></a>*powerqueue*.onAutostart&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This callback __onAutostart__ is defined in `PowerQueue`*
Is called when queue is auto started
> ```self.onAutostart = options && options.onAutostart || function() { ...``` [power-queue.js:115](power-queue.js#L115)
-
#### <a name="PowerQueue.total"></a>*powerqueue*.total()&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __total__ is defined in `PowerQueue`*
__Returns__ *{number}* __(is reactive)__
The total number of tasks added to this queue
> ```self.total = self._maxLength.get;``` [power-queue.js:123](power-queue.js#L123)
-
#### <a name="PowerQueue.isPaused"></a>*powerqueue*.isPaused()&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __isPaused__ is defined in `PowerQueue`*
__Returns__ *{boolean}* __(is reactive)__
Status of the paused state of the queue
> ```self.isPaused = self._paused.get;``` [power-queue.js:129](power-queue.js#L129)
-
#### <a name="PowerQueue.processing"></a>*powerqueue*.processing()&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __processing__ is defined in `PowerQueue`*
__Returns__ *{number}* __(is reactive)__
Number of tasks currently being processed
> ```self.processing = self._isProcessing.get;``` [power-queue.js:135](power-queue.js#L135)
-
#### <a name="PowerQueue.errors"></a>*powerqueue*.errors()&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __errors__ is defined in `PowerQueue`*
__Returns__ *{number}* __(is reactive)__
The total number of errors
Errors are triggered when [maxFailures](PowerQueue.maxFailures) are exeeded
> ```self.errors = self._errors.get;``` [power-queue.js:142](power-queue.js#L142)
-
#### <a name="PowerQueue.failures"></a>*powerqueue*.failures()&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __failures__ is defined in `PowerQueue`*
__Returns__ *{number}* __(is reactive)__
The total number of failed tasks
> ```self.failures = self._failures.get;``` [power-queue.js:148](power-queue.js#L148)
-
#### <a name="PowerQueue.isRunning"></a>*powerqueue*.isRunning()&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __isRunning__ is defined in `PowerQueue`*
__Returns__ *{boolean}* __(is reactive)__
True if the queue is running
> NOTE: The task can be paused but marked as running
> ```self.isRunning = self._running.get;``` [power-queue.js:155](power-queue.js#L155)
-
#### <a name="PowerQueue.maxProcessing"></a>*powerqueue*.maxProcessing([max])&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __maxProcessing__ is defined in `PowerQueue`*
__Arguments__
* __max__ *{number}* (Optional)
If not used this function works as a getter
-
__Returns__ *{number}* __(is reactive)__
Maximum number of simultaneous processing tasks
Example:
```js
foo.maxProcessing(); // Works as a getter and returns the current value
foo.maxProcessing(20); // This sets the value to 20
```
> ```self.maxProcessing = self._maxProcessing.getset;``` [power-queue.js:168](power-queue.js#L168)
-
#### <a name="PowerQueue.autostart"></a>*powerqueue*.autostart([autorun])&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __autostart__ is defined in `PowerQueue`*
__Arguments__
* __autorun__ *{boolean}* (Optional)
If not used this function works as a getter
-
__Returns__ *{boolean}* __(is reactive)__
If adding a task may trigger the queue to start
Example:
```js
foo.autostart(); // Works as a getter and returns the current value
foo.autostart(true); // This sets the value to true
```
> ```self.autostart = self._autostart.getset;``` [power-queue.js:189](power-queue.js#L189)
-
#### <a name="PowerQueue.maxFailures"></a>*powerqueue*.maxFailures([max])&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __maxFailures__ is defined in `PowerQueue`*
__Arguments__
* __max__ *{number}* (Optional)
If not used this function works as a getter
-
__Returns__ *{number}* __(is reactive)__
The maximum for failures pr. task before triggering an error
Example:
```js
foo.maxFailures(); // Works as a getter and returns the current value
foo.maxFailures(10); // This sets the value to 10
```
> ```self.maxFailures = self._maxFailures.getset;``` [power-queue.js:202](power-queue.js#L202)
-
#### <a name="PowerQueue.prototype.processList"></a>*powerqueue*.processList()&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __processList__ is defined in `prototype` of `PowerQueue`*
__Returns__ *{array}* __(is reactive)__
List of tasks currently being processed
> ```PowerQueue.prototype.processingList = function() { ...``` [power-queue.js:209](power-queue.js#L209)
-
#### <a name="PowerQueue.prototype.isHalted"></a>*powerqueue*.isHalted()&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __isHalted__ is defined in `prototype` of `PowerQueue`*
__Returns__ *{boolean}* __(is reactive)__
True if the queue is not running or paused
> ```PowerQueue.prototype.isHalted = function() { ...``` [power-queue.js:218](power-queue.js#L218)
-
#### <a name="PowerQueue.prototype.length"></a>*powerqueue*.length()&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __length__ is defined in `prototype` of `PowerQueue`*
__Returns__ *{number}* __(is reactive)__
Number of tasks left in queue to be processed
> ```PowerQueue.prototype.length = function() { ...``` [power-queue.js:227](power-queue.js#L227)
-
#### <a name="PowerQueue.prototype.progress"></a>*powerqueue*.progress()&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __progress__ is defined in `prototype` of `PowerQueue`*
__Returns__ *{number}* __(is reactive)__
0 .. 100 % Indicates the status of the queue
> ```PowerQueue.prototype.progress = function() { ...``` [power-queue.js:236](power-queue.js#L236)
-
#### <a name="PowerQueue.prototype.usage"></a>*powerqueue*.usage()&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __usage__ is defined in `prototype` of `PowerQueue`*
__Returns__ *{number}* __(is reactive)__
0 .. 100 % Indicates ressource usage of the queue
> ```PowerQueue.prototype.usage = function() { ...``` [power-queue.js:249](power-queue.js#L249)
-
#### <a name="PowerQueue.prototype.reset"></a>*powerqueue*.reset()&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __reset__ is defined in `prototype` of `PowerQueue`*
Calling this will:
* stop the queue
* paused to false
* Discart all queue data
> NOTE: At the moment if the queue has processing tasks they can change
> the `errors` and `failures` counters. This could change in the future or
> be prevented by creating a whole new instance of the `PowerQueue`
> ```PowerQueue.prototype.reset = function() { ...``` [power-queue.js:264](power-queue.js#L264)
-
#### <a name="PowerQueue._autoStartTasks"></a>*powerqueue*._autoStartTasks()&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method is private*
*This method ___autoStartTasks__ is defined in `PowerQueue`*
This method defines the autostart algorithm that allows add task to trigger
a start of the queue if queue is not paused.
> ```PowerQueue.prototype._autoStartTasks = function() { ...``` [power-queue.js:289](power-queue.js#L289)
-
#### <a name="PowerQueue.prototype.add"></a>*powerqueue*.add(data, [failures])&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __add__ is defined in `prototype` of `PowerQueue`*
__Arguments__
* __data__ *{any}*
The task to be handled
* __failures__ *{number}* (Optional)
Internally used to Pass on number of failures.
-
> ```PowerQueue.prototype.add = function(data, failures, id) { ...``` [power-queue.js:316](power-queue.js#L316)
-
#### <a name="PowerQueue.prototype.updateThrottleUp"></a>*powerqueue*.updateThrottleUp()&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method is private*
*This method __updateThrottleUp__ is defined in `prototype` of `PowerQueue`*
Calling this method will update the throttle on the queue adding tasks.
> Note: Currently we only support the PowerQueue - but we could support
> a more general interface for pauseable tasks or other usecases.
> ```PowerQueue.prototype.updateThrottleUp = function() { ...``` [power-queue.js:342](power-queue.js#L342)
-
#### <a name="PowerQueue.prototype.updateThrottleDown"></a>*powerqueue*.updateThrottleDown()&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method is private*
*This method __updateThrottleDown__ is defined in `prototype` of `PowerQueue`*
Calling this method will update the throttle on the queue pause tasks.
> Note: Currently we only support the PowerQueue - but we could support
> a more general interface for pauseable tasks or other usecases.
> ```PowerQueue.prototype.updateThrottleDown = function() { ...``` [power-queue.js:367](power-queue.js#L367)
-
#### <a name="PowerQueue.prototype.next"></a>*powerqueue*.next([err])&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __next__ is defined in `prototype` of `PowerQueue`*
__Arguments__
* __err__ *{string}* (Optional)
Error message if task failed
-
> * Can pass in `null` to start the queue
> * Passing in a string to `next` will trigger a failure
> * Passing nothing will simply let the next task run
`next` is handed into the [taskHandler](PowerQueue.taskHandler) as a
callback to mark an error or end of current task
> ```PowerQueue.prototype.next = function(err) { ...``` [power-queue.js:394](power-queue.js#L394)
-
#### <a name="done"></a>done&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
__Arguments__
* __feedback__ *{[Meteor.Error ](#Meteor.Error )|[ Error ](# Error )|[ String ](# String )|[ null](# null)}* (Optional)
This allows the task to communicate with the queue
-
Explaination of `feedback`
* `Meteor.Error` This means that the task failed in a controlled manner and is allowed to rerun
* `Error` This will throw the passed error - as its an unitended error
* `null` The task is not done yet, rerun later
* `String` The task can perform certain commands on the queue
* "pause" - pause the queue
* "stop" - stop the queue
* "reset" - reset the queue
* "cancel" - cancel the queue
> ```PowerQueue.prototype.runTaskDone = function(feedback, invocation) { ...``` [power-queue.js:452](power-queue.js#L452)
-
#### <a name="PowerQueue.prototype.runTaskDone"></a>*powerqueue*.runTaskDone([feedback], invocation)&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method is private*
*This method __runTaskDone__ is defined in `prototype` of `PowerQueue`*
__Arguments__
* __feedback__ *{[Meteor.Error ](#Meteor.Error )|[ Error ](# Error )|[ String ](# String )|[ null](# null)}* (Optional)
This allows the task to communicate with the queue
* __invocation__ *{object}*
-
> Note: `feedback` is explained in [Done callback](#done)
> ```PowerQueue.prototype.runTaskDone = function(feedback, invocation) { ...``` [power-queue.js:452](power-queue.js#L452)
-
#### <a name="PowerQueue.prototype.runTask"></a>*powerqueue*.runTask(invocation)&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method is private*
*This method __runTask__ is defined in `prototype` of `PowerQueue`*
__Arguments__
* __invocation__ *{object}*
The object stored in the micro-queue
-
> ```PowerQueue.prototype.runTask = function(invocation) { ...``` [power-queue.js:521](power-queue.js#L521)
-
#### <a name="PowerQueue.prototype.queueTaskHandler"></a>*powerqueue*.queueTaskHandler()&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __queueTaskHandler__ is defined in `prototype` of `PowerQueue`*
This method handles tasks that are sub queues
> ```PowerQueue.prototype.queueTaskHandler = function(subQueue, next, failures) { ...``` [power-queue.js:555](power-queue.js#L555)
-
#### <a name="PowerQueue.prototype.taskHandler"></a>*powerqueue*.taskHandler&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This callback __taskHandler__ is defined in `prototype` of `PowerQueue`*
__Arguments__
* __data__ *{any}*
This can be data or functions
* __next__ *{function}*
Function `next` call this to end task
* __failures__ *{number}*
Number of failures on this task
-
Default task handler expects functions as data:
```js
self.taskHandler = function(data, next, failures) {
// This default task handler expects invocation to be a function to run
if (typeof data !== 'function') {
throw new Error('Default task handler expects a function');
}
try {
// Have the function call next
data(next, failures);
} catch(err) {
// Throw to fail this task
next(err);
}
};
```
> ```PowerQueue.prototype.taskHandler = function(data, next, failures) { ...``` [power-queue.js:601](power-queue.js#L601)
-
#### <a name="PowerQueue.prototype.errorHandler"></a>*powerqueue*.errorHandler&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This callback __errorHandler__ is defined in `prototype` of `PowerQueue`*
__Arguments__
* __data__ *{any}*
This can be data or functions
* __addTask__ *{function}*
Use this function to insert the data into the queue again
* __failures__ *{number}*
Number of failures on this task
-
The default callback:
```js
var foo = new PowerQueue();
// Overwrite the default action
foo.errorHandler = function(data, addTask, failures) {
// This could be overwritten the data contains the task data and addTask
// is a helper for adding the task to the queue
// try again: addTask(data);
// console.log('Terminate at ' + failures + ' failures');
};
```
> ```PowerQueue.prototype.errorHandler = function(data, addTask, failures) { ...``` [power-queue.js:634](power-queue.js#L634)
-
#### <a name="PowerQueue.prototype.pause"></a>*powerqueue*.pause()&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __pause__ is defined in `prototype` of `PowerQueue`*
__TODO__
```
* We should have it pause all processing tasks
```
> ```PowerQueue.prototype.pause = function() { ...``` [power-queue.js:645](power-queue.js#L645)
-
#### <a name="PowerQueue.prototype.resume"></a>*powerqueue*.resume()&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __resume__ is defined in `prototype` of `PowerQueue`*
__TODO__
```
* We should have it resume all processing tasks
```
> This will not start a stopped queue
> ```PowerQueue.prototype.resume = function() { ...``` [power-queue.js:665](power-queue.js#L665)
-
#### <a name="PowerQueue.prototype.run"></a>*powerqueue*.run()&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __run__ is defined in `prototype` of `PowerQueue`*
> Using this command will resume a paused queue and will
> start a stopped queue.
> ```PowerQueue.prototype.run = function() { ...``` [power-queue.js:677](power-queue.js#L677)
-

View file

@ -0,0 +1,27 @@
Package.describe({
name: 'wekan-cfs-power-queue',
version: '0.9.11',
summary: "PowerQueue is a powerful tool for handling async tasks, throtling etc.",
git: 'https://github.com/zcfs/Meteor-power-queue.git'
});
Package.onUse(function (api) {
api.versionsFrom('1.0');
api.use(['deps', 'wekan-cfs-reactive-property@0.0.4'], ['client', 'server']);
// We let the user decide what spinal queue to use - We support both
// reactive-list and micro-queue they obey the spinal-queue spec
api.use(['wekan-cfs-reactive-list@0.0.9', 'wekan-cfs-micro-queue@0.0.6'], ['client', 'server'], { weak: true });
api.export && api.export('PowerQueue');
api.addFiles(['power-queue.js'], ['client', 'server']);
});
Package.onTest(function (api) {
api.use(['wekan-cfs-power-queue', 'wekan-cfs-reactive-list']);
api.use('test-helpers', ['server', 'client']);
api.use('tinytest');
api.addFiles('tests.js');
});

View file

@ -0,0 +1,727 @@
// Rig weak dependencies
if (typeof MicroQueue === 'undefined' && Package['micro-queue']) {
MicroQueue = Package['micro-queue'].MicroQueue;
}
if (typeof ReactiveList === 'undefined' && Package['reactive-list']) {
ReactiveList = Package['reactive-list'].ReactiveList;
}
// Rig weak dependencies in +0.9.1
if (typeof MicroQueue === 'undefined' && Package['wekan-cfs-micro-queue']) {
MicroQueue = Package['wekan-cfs-micro-queue'].MicroQueue;
}
if (typeof ReactiveList === 'undefined' && Package['wekan-cfs-reactive-list']) {
ReactiveList = Package['wekan-cfs-reactive-list'].ReactiveList;
}
/**
* Creates an instance of a power queue // Testing inline comment
* [Check out demo](http://power-queue-test.meteor.com/)
*
* @constructor
* @self powerqueue
* @param {object} [options] Settings
* @param {boolean} [options.filo=false] Make it a first in last out queue
* @param {boolean} [options.isPaused=false] Set queue paused
* @param {boolean} [options.autostart=true] May adding a task start the queue
* @param {string} [options.name="Queue"] Name of the queue
* @param {number} [options.maxProcessing=1] Limit of simultanous running tasks
* @param {number} [options.maxFailures = 5] Limit retries of failed tasks, if 0 or below we allow infinite failures
* @param {number} [options.jumpOnFailure = true] Jump to next task and retry failed task later
* @param {boolean} [options.debug=false] Log verbose messages to the console
* @param {boolean} [options.reactive=true] Set whether or not this queue should be reactive
* @param {boolean} [options.onAutostart] Callback for the queue autostart event
* @param {boolean} [options.onPaused] Callback for the queue paused event
* @param {boolean} [options.onReleased] Callback for the queue release event
* @param {boolean} [options.onEnded] Callback for the queue end event
* @param {[SpinalQueue](spinal-queue.spec.md)} [options.spinalQueue] Set spinal queue uses pr. default `MicroQueue` or `ReactiveList` if added to the project
*/
PowerQueue = function(options) {
var self = this;
var test = 5;
self.reactive = (options && options.reactive === false) ? false : true;
// Allow user to use another micro-queue #3
// We try setting the ActiveQueue to MicroQueue if installed in the app
var ActiveQueue = (typeof MicroQueue !== 'undefined') && MicroQueue || undefined;
// If ReactiveList is added to the project we use this over MicroQueue
ActiveQueue = (typeof ReactiveList !== 'undefined') && ReactiveList || ActiveQueue;
// We allow user to overrule and set a custom spinal-queue spec complient queue
if (options && typeof options.spinalQueue !== 'undefined') {
ActiveQueue = options.spinalQueue;
}
if (typeof ActiveQueue === 'undefined') {
console.log('Error: You need to add a spinal queue to the project');
console.log('Please add "micro-queue", "reactive-list" to the project');
throw new Error('Please add "micro-queue", "reactive-list" or other spinalQueue compatible packages');
}
// Default is fifo lilo
self.invocations = new ActiveQueue({
//
sort: (options && (options.filo || options.lifo)),
reactive: self.reactive
});
//var self.invocations = new ReactiveList(queueOrder);
// List of current tasks being processed
self._processList = new ActiveQueue({
reactive: self.reactive
}); //ReactiveList();
// Max number of simultanious tasks being processed
self._maxProcessing = new ReactiveProperty(options && options.maxProcessing || 1, self.reactive);
// Reactive number of tasks being processed
self._isProcessing = new ReactiveProperty(0, self.reactive);
// Boolean indicating if queue is paused or not
self._paused = new ReactiveProperty((options && options.isPaused || false), self.reactive);
// Boolean indicator for queue status active / running (can still be paused)
self._running = new ReactiveProperty(false, self.reactive);
// Counter for errors, errors are triggered if maxFailures is exeeded
self._errors = new ReactiveProperty(0, self.reactive);
// Counter for task failures, contains error count
self._failures = new ReactiveProperty(0, self.reactive);
// On failure jump to new task - if false the current task is rerun until error
self._jumpOnFailure = (options && options.jumpOnFailure === false) ? false : true;
// Count of all added tasks
self._maxLength = new ReactiveProperty(0, self.reactive);
// Boolean indicate whether or not a "add" task is allowed to start the queue
self._autostart = new ReactiveProperty( ((options && options.autostart === false) ? false : true), self.reactive);
// Limit times a task is allowed to fail and be rerun later before triggering an error
self._maxFailures = new ReactiveProperty( (options && options.maxFailures || 5), self.reactive);
// Name / title of this queue - Not used - should deprecate
self.title = options && options.name || 'Queue';
// debug - will print error / failures passed to next
self.debug = !!(options && options.debug);
/** @method PowerQueue.total
* @reactive
* @returns {number} The total number of tasks added to this queue
*/
self.total = self._maxLength.get;
/** @method PowerQueue.isPaused
* @reactive
* @returns {boolean} Status of the paused state of the queue
*/
self.isPaused = self._paused.get;
/** @method PowerQueue.processing
* @reactive
* @returns {number} Number of tasks currently being processed
*/
self.processing = self._isProcessing.get;
/** @method PowerQueue.errors
* @reactive
* @returns {number} The total number of errors
* Errors are triggered when [maxFailures](PowerQueue.maxFailures) are exeeded
*/
self.errors = self._errors.get;
/** @method PowerQueue.failures
* @reactive
* @returns {number} The total number of failed tasks
*/
self.failures = self._failures.get;
/** @method PowerQueue.isRunning
* @reactive
* @returns {boolean} True if the queue is running
* > NOTE: The task can be paused but marked as running
*/
self.isRunning = self._running.get;
/** @method PowerQueue.maxProcessing Get setter for maxProcessing
* @param {number} [max] If not used this function works as a getter
* @reactive
* @returns {number} Maximum number of simultaneous processing tasks
*
* Example:
* ```js
* foo.maxProcessing(); // Works as a getter and returns the current value
* foo.maxProcessing(20); // This sets the value to 20
* ```
*/
self.maxProcessing = self._maxProcessing.getset;
self._maxProcessing.onChange = function() {
// The user can change the max allowed processing tasks up or down here...
// Update the throttle up
self.updateThrottleUp();
// Update the throttle down
self.updateThrottleDown();
};
/** @method PowerQueue.autostart Get setter for autostart
* @param {boolean} [autorun] If not used this function works as a getter
* @reactive
* @returns {boolean} If adding a task may trigger the queue to start
*
* Example:
* ```js
* foo.autostart(); // Works as a getter and returns the current value
* foo.autostart(true); // This sets the value to true
* ```
*/
self.autostart = self._autostart.getset;
/** @method PowerQueue.maxFailures Get setter for maxFailures
* @param {number} [max] If not used this function works as a getter
* @reactive
* @returns {number} The maximum for failures pr. task before triggering an error
*
* Example:
* ```js
* foo.maxFailures(); // Works as a getter and returns the current value
* foo.maxFailures(10); // This sets the value to 10
* ```
*/
self.maxFailures = self._maxFailures.getset;
/** @callback PowerQueue.onPaused
* Is called when queue is ended
*/
self.onPaused = options && options.onPaused || function() {
self.debug && console.log(self.title + ' ENDED');
};
/** @callback PowerQueue.onEnded
* Is called when queue is ended
*/
self.onEnded = options && options.onEnded || function() {
self.debug && console.log(self.title + ' ENDED');
};
/** @callback PowerQueue.onRelease
* Is called when queue is released
*/
self.onRelease = options && options.onRelease || function() {
self.debug && console.log(self.title + ' RELEASED');
};
/** @callback PowerQueue.onAutostart
* Is called when queue is auto started
*/
self.onAutostart = options && options.onAutostart || function() {
self.debug && console.log(self.title + ' Autostart');
};
};
/** @method PowerQueue.prototype.processList
* @reactive
* @returns {array} List of tasks currently being processed
*/
PowerQueue.prototype.processingList = function() {
var self = this;
return self._processList.fetch();
};
/** @method PowerQueue.prototype.isHalted
* @reactive
* @returns {boolean} True if the queue is not running or paused
*/
PowerQueue.prototype.isHalted = function() {
var self = this;
return (!self._running.get() || self._paused.get());
};
/** @method PowerQueue.prototype.length
* @reactive
* @returns {number} Number of tasks left in queue to be processed
*/
PowerQueue.prototype.length = function() {
var self = this;
return self.invocations.length();
};
/** @method PowerQueue.prototype.progress
* @reactive
* @returns {number} 0 .. 100 % Indicates the status of the queue
*/
PowerQueue.prototype.progress = function() {
var self = this;
var progress = self._maxLength.get() - self.invocations.length() - self._isProcessing.get();
if (self._maxLength.value > 0) {
return Math.round(progress / self._maxLength.value * 100);
}
return 0;
};
/** @method PowerQueue.prototype.usage
* @reactive
* @returns {number} 0 .. 100 % Indicates resource usage of the queue
*/
PowerQueue.prototype.usage = function() {
var self = this;
return Math.round(self._isProcessing.get() / self._maxProcessing.get() * 100);
};
/** @method PowerQueue.prototype.reset Reset the queue
* Calling this will:
* * stop the queue
* * paused to false
* * Discart all queue data
*
* > NOTE: At the moment if the queue has processing tasks they can change
* > the `errors` and `failures` counters. This could change in the future or
* > be prevented by creating a whole new instance of the `PowerQueue`
*/
PowerQueue.prototype.reset = function() {
var self = this;
self.debug && console.log(self.title + ' RESET');
self._running.set(false);
self._paused.set(false);
self.invocations.reset();
self._processList.reset();
// // Loop through the processing tasks and reset these
// self._processList.forEach(function(data) {
// if (data.queue instanceof PowerQueue) {
// data.queue.reset();
// }
// }, true);
self._maxLength.set(0);
self._failures.set(0);
self._errors.set(0);
};
/** @method PowerQueue._autoStartTasks
* @private
*
* This method defines the autostart algorithm that allows add task to trigger
* a start of the queue if queue is not paused.
*/
PowerQueue.prototype._autoStartTasks = function() {
var self = this;
// We dont start anything by ourselfs if queue is paused
if (!self._paused.value) {
// Queue is not running and we are set to autostart so we start the queue
if (!self._running.value && self._autostart.value) {
// Trigger callback / event
self.onAutostart();
// Set queue as running
self._running.set(true);
}
// Make sure that we use all available resources
if (self._running.value) {
// Call next to start up the queue
self.next(null);
}
}
};
/** @method PowerQueue.prototype.add
* @param {any} data The task to be handled
* @param {number} [failures] Used internally to Pass on number of failures.
*/
PowerQueue.prototype.add = function(data, failures, id) {
var self = this;
// Assign new id to task
var assignNewId = self._jumpOnFailure || typeof id === 'undefined';
// Set the task id
var taskId = (assignNewId) ? self._maxLength.value + 1 : id;
// self.invocations.add({ _id: currentId, data: data, failures: failures || 0 }, reversed);
self.invocations.insert(taskId, { _id: taskId, data: data, failures: failures || 0 });
// If we assigned new id then increase length
if (assignNewId) self._maxLength.inc();
self._autoStartTasks();
};
/** @method PowerQueue.prototype.updateThrottleUp
* @private
*
* Calling this method will update the throttle on the queue adding tasks.
*
* > Note: Currently we only support the PowerQueue - but we could support
* > a more general interface for pauseable tasks or other usecases.
*/
PowerQueue.prototype.updateThrottleUp = function() {
var self = this;
// How many additional tasks can we handle?
var availableSlots = self._maxProcessing.value - self._isProcessing.value;
// If we can handle more, we have more, we're running, and we're not paused
if (!self._paused.value && self._running.value && availableSlots > 0 && self.invocations._length > 0) {
// Increase counter of current number of tasks being processed
self._isProcessing.inc();
// Run task
self.runTask(self.invocations.getFirstItem());
// Repeat recursively; this is better than a for loop to avoid blocking the UI
self.updateThrottleUp();
}
};
/** @method PowerQueue.prototype.updateThrottleDown
* @private
*
* Calling this method will update the throttle on the queue pause tasks.
*
* > Note: Currently we only support the PowerQueue - but we could support
* > a more general interface for pauseable tasks or other usecases.
*/
PowerQueue.prototype.updateThrottleDown = function() {
var self = this;
// Calculate the differece between acutuall processing tasks and target
var diff = self._isProcessing.value - self._maxProcessing.value;
// If the diff is more than 0 then we have many tasks processing.
if (diff > 0) {
// We pause the latest added tasks
self._processList.forEachReverse(function(data) {
if (diff > 0 && data.queue instanceof PowerQueue) {
diff--;
// We dont mind calling pause on multiple times on each task
// theres a simple check going on preventing any duplicate actions
data.queue.pause();
}
}, true);
}
};
/** @method PowerQueue.prototype.next
* @param {string} [err] Error message if task failed
* > * Can pass in `null` to start the queue
* > * Passing in a string to `next` will trigger a failure
* > * Passing nothing will simply let the next task run
* `next` is handed into the [taskHandler](PowerQueue.taskHandler) as a
* callback to mark an error or end of current task
*/
PowerQueue.prototype.next = function(err) {
var self = this;
// Primary concern is to throttle up because we are either:
// 1. Starting the queue
// 2. Starting next task
//
// This function does not shut down running tasks
self.updateThrottleUp();
// We are running, no tasks are being processed even we just updated the
// throttle up and we got no errors.
// 1. We are paused and releasing tasks
// 2. We are done
if (self._running.value && self._isProcessing.value === 0 && err !== null) {
// We have no tasks processing so this queue is now releasing resources
// this could be that the queue is paused or stopped, in that case the
// self.invocations._length would be > 0
// If on the other hand the self.invocations._length is 0 then we have no more
// tasks in the queue so the queue has ended
self.onRelease(self.invocations._length);
if (!self.invocations._length) { // !self._paused.value &&
// Check if queue is done working
// Stop the queue
self._running.set(false);
// self.invocations.reset(); // This should be implicit
self.onEnded();
}
}
};
/** @callback done
* @param {Meteor.Error | Error | String | null} [feedback] This allows the task to communicate with the queue
*
* Explaination of `feedback`
* * `Meteor.Error` This means that the task failed in a controlled manner and is allowed to rerun
* * `Error` This will throw the passed error - as its an unitended error
* * `null` The task is not done yet, rerun later
* * `String` The task can perform certain commands on the queue
* * "pause" - pause the queue
* * "stop" - stop the queue
* * "reset" - reset the queue
* * "cancel" - cancel the queue
*
*/
/** @method PowerQueue.prototype.runTaskDone
* @private
* @param {Meteor.Error | Error | String | null} [feedback] This allows the task to communicate with the queue
* @param {object} invocation
*
* > Note: `feedback` is explained in [Done callback](#done)
*
*/
// Rig the callback function
PowerQueue.prototype.runTaskDone = function(feedback, invocation) {
var self = this;
// If the task handler throws an error then add it to the queue again
// we allow this for a max of self._maxFailures
// If the error is null then we add the task silently back into the
// microQueue in reverse... This could be due to pause or throttling
if (feedback instanceof Meteor.Error) {
// We only count failures if maxFailures are above 0
if (self._maxFailures.value > 0) invocation.failures++;
self._failures.inc();
// If the user has set the debug flag we print out failures/errors
self.debug && console.error('Error: "' + self.title + '" ' + feedback.message + ', ' + feedback.stack);
if (invocation.failures < self._maxFailures.value) {
// Add the task again with the increased failures
self.add(invocation.data, invocation.failures, invocation._id);
} else {
self._errors.inc();
self.errorHandler(invocation.data, self.add, invocation.failures);
}
// If a error is thrown we assume its not intended
} else if (feedback instanceof Error) throw feedback;
if (feedback)
// We use null to throttle pauseable tasks
if (feedback === null) {
// We add this task into the queue, no questions asked
self.invocations.insert(invocation._id, { data: invocation.data, failures: invocation.failures, _id: invocation._id });
}
// If the user returns a string we got a command
if (feedback === ''+feedback) {
var command = {
'pause': function() { self.pause(); },
'stop': function() { self.stop(); },
'reset': function() { self.reset(); },
'cancel': function() { self.cancel(); },
};
if (typeof command[feedback] === 'function') {
// Run the command on this queue
command[feedback]();
} else {
// We dont recognize this command, throw an error
throw new Error('Unknown queue command "' + feedback + '"');
}
}
// Decrease the number of tasks being processed
// make sure we dont go below 0
if (self._isProcessing.value > 0) self._isProcessing.dec();
// Task has ended we remove the task from the process list
self._processList.remove(invocation._id);
invocation.data = null;
invocation.failures = null;
invocation._id = null;
invocation = null;
delete invocation;
// Next task
Meteor.setTimeout(function() {
self.next();
}, 0);
};
/** @method PowerQueue.prototype.runTask
* @private // This is not part of the open api
* @param {object} invocation The object stored in the micro-queue
*/
PowerQueue.prototype.runTask = function(invocation) {
var self = this;
// We start the fitting task handler
// Currently we only support the PowerQueue but we could have a more general
// interface for tasks that allow throttling
try {
if (invocation.data instanceof PowerQueue) {
// Insert PowerQueue into process list
self._processList.insert(invocation._id, { id: invocation._id, queue: invocation.data });
// Handle task
self.queueTaskHandler(invocation.data, function subQueueCallbackDone(feedback) {
self.runTaskDone(feedback, invocation);
}, invocation.failures);
} else {
// Insert task into process list
self._processList.insert(invocation._id, invocation.data);
// Handle task
self.taskHandler(invocation.data, function taskCallbackDone(feedback) {
self.runTaskDone(feedback, invocation);
}, invocation.failures);
}
} catch(err) {
throw new Error('Error while running taskHandler for queue, Error: ' + err.message);
}
};
/** @method PowerQueue.prototype.queueTaskHandler
* This method handles tasks that are sub queues
*/
PowerQueue.prototype.queueTaskHandler = function(subQueue, next, failures) {
var self = this;
// Monitor sub queue task releases
subQueue.onRelease = function(remaining) {
// Ok, we were paused - this could be throttling so we respect this
// So when the queue is halted we add it back into the main queue
if (remaining > 0) {
// We get out of the queue but dont repport error and add to run later
next(null);
} else {
// Queue has ended
// We simply trigger next task when the sub queue is complete
next();
// When running subqueues it doesnt make sense to track failures and retry
// the sub queue - this is sub queue domain
}
};
// Start the queue
subQueue.run();
};
/** @callback PowerQueue.prototype.taskHandler
* @param {any} data This can be data or functions
* @param {function} next Function `next` call this to end task
* @param {number} failures Number of failures on this task
*
* Default task handler expects functions as data:
* ```js
* self.taskHandler = function(data, next, failures) {
* // This default task handler expects invocation to be a function to run
* if (typeof data !== 'function') {
* throw new Error('Default task handler expects a function');
* }
* try {
* // Have the function call next
* data(next, failures);
* } catch(err) {
* // Throw to fail this task
* next(err);
* }
* };
* ```
*/
// Can be overwrittin by the user
PowerQueue.prototype.taskHandler = function(data, next, failures) {
var self = this;
// This default task handler expects invocation to be a function to run
if (typeof data !== 'function') {
throw new Error('Default task handler expects a function');
}
try {
// Have the function call next
data(next, failures);
} catch(err) {
// Throw to fail this task
next(err);
}
};
/** @callback PowerQueue.prototype.errorHandler
* @param {any} data This can be data or functions
* @param {function} addTask Use this function to insert the data into the queue again
* @param {number} failures Number of failures on this task
*
* The default callback:
* ```js
* var foo = new PowerQueue();
*
* // Overwrite the default action
* foo.errorHandler = function(data, addTask, failures) {
* // This could be overwritten the data contains the task data and addTask
* // is a helper for adding the task to the queue
* // try again: addTask(data);
* // console.log('Terminate at ' + failures + ' failures');
* };
* ```
*/
PowerQueue.prototype.errorHandler = function(data, addTask, failures) {
var self = this;
// This could be overwritten the data contains the task data and addTask
// is a helper for adding the task to the queue
// try again: addTask(data);
self.debug && console.log('Terminate at ' + failures + ' failures');
};
/** @method PowerQueue.prototype.pause Pause the queue
* @todo We should have it pause all processing tasks
*/
PowerQueue.prototype.pause = function() {
var self = this;
if (!self._paused.value) {
self._paused.set(true);
// Loop through the processing tasks and pause these
self._processList.forEach(function(data) {
if (data.queue instanceof PowerQueue) {
// Pause the sub queue
data.queue.pause();
}
}, true);
// Trigger callback
self.onPaused();
}
};
/** @method PowerQueue.prototype.resume Start a paused queue
* @todo We should have it resume all processing tasks
*
* > This will not start a stopped queue
*/
PowerQueue.prototype.resume = function() {
var self = this;
self.run();
};
/** @method PowerQueue.prototype.run Starts the queue
* > Using this command will resume a paused queue and will
* > start a stopped queue.
*/
PowerQueue.prototype.run = function() {
var self = this;
//not paused and already running or queue empty or paused subqueues
if (!self._paused.value && self._running.value || !self.invocations._length) {
return;
}
self._paused.set(false);
self._running.set(true);
self.next(null);
};
/** @method PowerQueue.prototype.stop Stops the queue
*/
PowerQueue.prototype.stop = function() {
var self = this;
self._running.set(false);
};
/** @method PowerQueue.prototype.cancel Cancel the queue
*/
PowerQueue.prototype.cancel = function() {
var self = this;
self.reset();
};

View file

@ -0,0 +1,151 @@
#Spinal Queue Spec
This specification declares the interface for the "spinal" queue in `PowerQueue`.
We allready have two implementations the [MicroQueue](https://github.com/zcfs/Meteor-micro-queue) and [ReactiveList](https://github.com/zcfs/Meteor-reactive-list)
#SpinalQueue
Provides a simple reactive list interface
#### <a name="SpinalQueue"></a>new SpinalQueue(lifo)&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
__Arguments__
* __lifo__ *{boolean}*
Set the order of the queue default is `fifo`
-
Example:
```js
var list = new SpinalQueue();
list.insert(1, { text: 'Hello id: 1' });
list.insert(2, { text: 'Hello id: 2' });
list.insert(3, { text: 'Hello id: 3' });
list.update(2, { text: 'Updated 2'});
list.remove(1);
list.forEach(function(value, key) {
console.log('GOT: ' + value.text);
}, true); // Set noneReactive = true, default behaviour is reactive
// Return from Template:
Template.hello.list = function() {
return list.fetch();
};
```
-
#### <a name="SpinalQueue.length"></a>*SpinalQueue*.length()&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __length__ is defined in `SpinalQueue`*
__Returns__ *{number}* __(is reactive)__
Length of the reactive list
-
#### <a name="SpinalQueue.reset"></a>*SpinalQueue*.reset()&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __reset__ is defined in `SpinalQueue`*
-
#### <a name="SpinalQueue.update"></a>*SpinalQueue*.update(key, value)&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __update__ is defined in `SpinalQueue`*
__Arguments__
* __key__ *{string|number}*
Key to update
* __value__ *{any}*
Update with this value
> Note: Method is currently not used by `PowerQueue`
-
#### <a name="SpinalQueue.insert"></a>*SpinalQueue*.insert(key, value)&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __insert__ is defined in `SpinalQueue`*
__Arguments__
* __key__ *{string|number}*
Key to insert
* __value__ *{any}*
Insert item with this value
-
#### <a name="SpinalQueue.remove"></a>*SpinalQueue*.remove(key)&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __remove__ is defined in `SpinalQueue`*
__Arguments__
* __key__ *{string|number}*
Key to remove
-
#### <a name="SpinalQueue.getLastItem"></a>*SpinalQueue*.getLastItem()&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __getLastItem__ is defined in `SpinalQueue`*
__Returns__ *{any}*
Pops last item from the list - removes the item from the list
> Note: Method is currently not used by `PowerQueue`
-
#### <a name="SpinalQueue.getFirstItem"></a>*SpinalQueue*.getFirstItem()&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __getFirstItem__ is defined in `SpinalQueue`*
__Returns__ *{any}*
Pops first item from the list - removes the item from the list
#### <a name="SpinalQueue.forEach"></a>*SpinalQueue*.forEach(f, [noneReactive], [reverse])&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __forEach__ is defined in `SpinalQueue`*
__Arguments__
* __f__ *{function}*
Callback `funciton(value, key)`
* __noneReactive__ *{boolean}* (Optional = false)
Set true if want to disable reactivity
-
#### <a name="SpinalQueue.forEachReverse"></a>*SpinalQueue*.forEachReverse(f, [noneReactive])&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __forEachReverse__ is defined in `SpinalQueue`*
__Arguments__
* __f__ *{function}*
Callback `funciton(value, key)`
* __noneReactive__ *{boolean}* (Optional = false)
Set true if want to disable reactivity
-
#### <a name="SpinalQueue.fetch"></a>*SpinalQueue*.fetch([noneReactive])&nbsp;&nbsp;<sub><i>Anywhere</i></sub> ####
-
*This method __fetch__ is defined in `SpinalQueue`*
__Arguments__
* __noneReactive__ *{boolean}* (Optional = false)
Set true if want to disable reactivity
-
__Returns__ *{array}* __(is reactive)__
List of items
-

View file

@ -0,0 +1,198 @@
"use strict";
function equals(a, b) {
return !!(JSON.stringify(a) === JSON.stringify(b));
}
Tinytest.add('PowerQueue - scope', function(test) {
test.isTrue(typeof PowerQueue !== 'undefined', 'The PowerQueue scope is missing, please add the power-queue package');
});
// We run 5 tasks in serial mode
Tinytest.addAsync('PowerQueue - test serial run', function (test, onComplete) {
var queue = new PowerQueue({
name: 'test queue 1',
autostart: false,
maxProcessing: 1,
debug: true,
// When this task is released we do our tests
onEnded: function() {
console.log('It ended');
// Check that we ran the expected number of tasks
test.equal(counter, 5, 'counter did not match number of tasks');
// Check that the result was correct
test.equal(result, expectedResult, 'result was unexpected');
// We are done testing
onComplete();
}
});
var result = '';
var expectedResult = '12345';
var counter = 0;
var checkCounter = function(id, next) {
console.log('test queue 1 - Run task: ' + id);
// Keep a counter
counter++;
// push id to result
result += id;
// call next task
next();
};
// Add the tasks to the queue
queue.add(function(next) { checkCounter('1', next); });
queue.add(function(next) { checkCounter('2', next); });
queue.add(function(next) { checkCounter('3', next); });
queue.add(function(next) { checkCounter('4', next); });
queue.add(function(next) { checkCounter('5', next); });
// Run the queue
queue.run();
});
// We run 5 tasks in serial mode but pause the queue on 3
Tinytest.addAsync('PowerQueue - test serial pause', function (test, onComplete) {
var queue = new PowerQueue({
name: 'test queue 2',
autostart: false,
maxProcessing: 1,
debug: true,
// When this task is released we do our tests
onPaused: function() {
console.log('Its paused');
// Check that we ran the expected number of tasks
test.equal(counter, 3, 'counter did not match number of tasks');
// Check that the result was correct
test.equal(result, expectedResult, 'result was unexpected');
// We are done testing
onComplete();
}
});
var result = '';
var expectedResult = '123';
var counter = 0;
var checkCounter = function(id, next) {
console.log('test queue 2 - Run task: ' + id);
// Keep a counter
counter++;
// push id to result
result += id;
// call next task
if (id === '3')
next('pause')
else
next();
};
// Add the tasks to the queue
queue.add(function(next) { checkCounter('1', next); });
queue.add(function(next) { checkCounter('2', next); });
queue.add(function(next) { checkCounter('3', next); });
queue.add(function(next) { checkCounter('4', next); });
queue.add(function(next) { checkCounter('5', next); });
// Run the queue
queue.run();
});
// We run 5 tasks in serial mode but pause the queue on 3
Tinytest.addAsync('PowerQueue - test 2 task in parallel', function (test, onComplete) {
var queue = new PowerQueue({
name: 'test queue 3',
autostart: false,
maxProcessing: 2,
debug: true,
// When this task is released we do our tests
onEnded: function() {
console.log('Its paused');
// Check that we ran the expected number of tasks
test.equal(counter, 10, 'counter did not match number of tasks');
// Check that the result was correct
test.equal(result, expectedResult, 'result was unexpected');
// We are done testing
onComplete();
}
});
// start 1-----3-------4-------6------------------------9-----------------------X
// 2-----------------5---------------7--------8-----------10------X
// ms 0 5 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100
// result 1 2 3 4 5 6 7 8 9 10
// result 1 3 2 4 5 7 6 8 10 9
var wait = {
'1': 10,
'2': 25,
'3': 10,
'4': 10,
'5': 20,
'6': 30,
'7': 10,
'8': 15,
'9': 30,
'10': 10,
};
// 1324
var result = '';
var expectedResult = '13245768109';
var counter = 0;
var checkCounter = function(id, next) {
console.log('test queue 3 - Run task: ' + id);
// Keep a counter
counter++;
// push id to result
Meteor.setTimeout(function() {
result += id;
// call next task
next();
}, wait[id] * 5); // give it a factor 2 to make sure we get the correct result
};
// Add the tasks to the queue
queue.add(function(next) { checkCounter('1', next); });
queue.add(function(next) { checkCounter('2', next); });
queue.add(function(next) { checkCounter('3', next); });
queue.add(function(next) { checkCounter('4', next); });
queue.add(function(next) { checkCounter('5', next); });
queue.add(function(next) { checkCounter('6', next); });
queue.add(function(next) { checkCounter('7', next); });
queue.add(function(next) { checkCounter('8', next); });
queue.add(function(next) { checkCounter('9', next); });
queue.add(function(next) { checkCounter('10', next); });
// Run the queue
queue.run();
});
//Test API:
//test.isFalse(v, msg)
//test.isTrue(v, msg)
//test.equal(actual, expected, message, not)
//test.length(obj, len)
//test.include(s, v)
//test.isNaN(v, msg)
//test.isUndefined(v, msg)
//test.isNotNull
//test.isNull
//test.throws(func)
//test.instanceOf(obj, klass)
//test.notEqual(actual, expected, message)
//test.runId()
//test.exception(exception)
//test.expect_fail()
//test.ok(doc)
//test.fail(doc)
//test.equal(a, b, msg)