aboutsummaryrefslogtreecommitdiff
path: root/node_modules/seq-queue
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/seq-queue')
-rw-r--r--node_modules/seq-queue/.jshintrc19
-rw-r--r--node_modules/seq-queue/.npmignore3
-rw-r--r--node_modules/seq-queue/AUTHORS1
-rw-r--r--node_modules/seq-queue/LICENSE22
-rw-r--r--node_modules/seq-queue/Makefile9
-rw-r--r--node_modules/seq-queue/README.md75
-rw-r--r--node_modules/seq-queue/index.js1
-rw-r--r--node_modules/seq-queue/lib/.npmignore0
-rw-r--r--node_modules/seq-queue/lib/seq-queue.js199
-rw-r--r--node_modules/seq-queue/package.json17
-rw-r--r--node_modules/seq-queue/test/seq-queue-test.js307
11 files changed, 653 insertions, 0 deletions
diff --git a/node_modules/seq-queue/.jshintrc b/node_modules/seq-queue/.jshintrc
new file mode 100644
index 0000000..bb3389c
--- /dev/null
+++ b/node_modules/seq-queue/.jshintrc
@@ -0,0 +1,19 @@
+{
+ "predef": [
+ "describe",
+ "it",
+ "before",
+ "after",
+ "window",
+ "__resources__"
+ ],
+ "es5": true,
+ "node": true,
+ "eqeqeq": true,
+ "undef": true,
+ "curly": true,
+ "bitwise": true,
+ "immed": false,
+ "newcap": true,
+ "nonew": true
+}
diff --git a/node_modules/seq-queue/.npmignore b/node_modules/seq-queue/.npmignore
new file mode 100644
index 0000000..3995665
--- /dev/null
+++ b/node_modules/seq-queue/.npmignore
@@ -0,0 +1,3 @@
+.project
+node_modules/
+lib/doc/
diff --git a/node_modules/seq-queue/AUTHORS b/node_modules/seq-queue/AUTHORS
new file mode 100644
index 0000000..5174d23
--- /dev/null
+++ b/node_modules/seq-queue/AUTHORS
@@ -0,0 +1 @@
+* Yongchang Zhou <changchang005@gmail.com> \ No newline at end of file
diff --git a/node_modules/seq-queue/LICENSE b/node_modules/seq-queue/LICENSE
new file mode 100644
index 0000000..d4e3221
--- /dev/null
+++ b/node_modules/seq-queue/LICENSE
@@ -0,0 +1,22 @@
+(The MIT License)
+
+Copyright (c) 2012 Netease, Inc. and other pomelo contributors
+
+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.
diff --git a/node_modules/seq-queue/Makefile b/node_modules/seq-queue/Makefile
new file mode 100644
index 0000000..76354ea
--- /dev/null
+++ b/node_modules/seq-queue/Makefile
@@ -0,0 +1,9 @@
+TESTS = test/*.js
+REPORTER = spec
+TIMEOUT = 5000
+
+test:
+ @./node_modules/.bin/mocha \
+ --reporter $(REPORTER) --timeout $(TIMEOUT) $(TESTS)
+
+.PHONY: test \ No newline at end of file
diff --git a/node_modules/seq-queue/README.md b/node_modules/seq-queue/README.md
new file mode 100644
index 0000000..4f21a71
--- /dev/null
+++ b/node_modules/seq-queue/README.md
@@ -0,0 +1,75 @@
+seq-queue - queue to keep request process in sequence
+=====================================================
+
+Seq-queue is simple tool to keep requests to be executed in order.
+
+As we known, Node.js codes run in asynchronous mode and the callbacks are unordered. But sometimes we may need the requests to be processed in order. For example, in a game, a player would do some operations such as turn right and go ahead. And in the server side, we would like to process these requests one by one, not do them all at the same time.
+
+Seq-queue takes the responsibility to make the asynchronous, unordered processing flow into serial and ordered. It's simple but not a repeated wheel.
+
+Seq-queue is a FIFO task queue and we can push tasks as we wish, anytime(before the queue closed), anywhere(if we hold the queue instance). A task is known as a function and we can do anything in the function and just need to call `task.done()` to tell the queue current task has finished. It promises that a task in queue would not be executed util all tasks before it finished.
+
+Seq-queue add timeout for each task execution. If a task throws an uncaught exception in its call back or a developer forgets to call `task.done()` callback, queue would be blocked and would not execute the left tasks. To avoid these situations, seq-queue set a timeout for each task. If a task timeout, queue would drop the task and notify develop by a 'timeout' event and then invoke the next task. Any `task.done()` invoked in a timeout task would be ignored.
+
+ * Tags: node.js
+
+##Installation
+```
+npm install seq-queue
+```
+
+##Usage
+``` javascript
+var seqqueue = require('seq-queue');
+
+var queue = seqqueue.createQueue(1000);
+
+queue.push(
+ function(task) {
+ setTimeout(function() {
+ console.log('hello ');
+ task.done();
+ }, 500);
+ },
+ function() {
+ console.log('task timeout');
+ },
+ 1000
+);
+
+queue.push(
+ function(task) {
+ setTimeout(function() {
+ console.log('world~');
+ task.done();
+ }, 500);
+ }
+);
+```
+
+##API
+###seqqueue.createQueue(timeout)
+Create a new queue instance. A global timeout value in ms for the new instance can be set by `timeout` parameter or use the default timeout (3s) by no parameter.
+
+###queue.push(fn, ontimeout, timeout)
+Add a task into the queue instance.
+####Arguments
++ fn(task) - The function that describes the content of task and would be invoke by queue. `fn` takes a arguemnt task and we *must* call task.done() to tell queue current task has finished.
++ ontimeout() - Callback for task timeout.
++ timeout - Timeout in ms for `fn`. If specified, it would overwrite the global timeout that set by `createQueue` for `fn`.
+
+###queue.close(force)
+Close the queue. A closed queue would stop receiving new task immediately. And the left tasks would be treated in different ways decided by `force`.
+####Arguments
++ force - If true, queue would stop working immediately and ignore any tasks left in queue. Otherwise queue would execute the tasks in queue and then stop.
+
+##Event
+Seq-queue instances extend the EventEmitter and would emit events in their life cycles.
+###'timeout'(totask)
+If current task not invoke task.done() within the timeout ms, a timeout event would be emit. totask.fn and totask.timeout is the `fn` and `timeout` arguments that passed by `queue.push(2)`.
+###'error'(err, task)
+If the task function (not callbacks) throws an uncaught error, queue would emit an error event and passes the err and task informations by event callback arguments.
+###'closed'
+Emit when the close(false) is invoked.
+###'drained'
+Emit when close(true) is invoked or all tasks left have finished in closed status.
diff --git a/node_modules/seq-queue/index.js b/node_modules/seq-queue/index.js
new file mode 100644
index 0000000..51029d8
--- /dev/null
+++ b/node_modules/seq-queue/index.js
@@ -0,0 +1 @@
+module.exports = require('./lib/seq-queue'); \ No newline at end of file
diff --git a/node_modules/seq-queue/lib/.npmignore b/node_modules/seq-queue/lib/.npmignore
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/node_modules/seq-queue/lib/.npmignore
diff --git a/node_modules/seq-queue/lib/seq-queue.js b/node_modules/seq-queue/lib/seq-queue.js
new file mode 100644
index 0000000..f13f285
--- /dev/null
+++ b/node_modules/seq-queue/lib/seq-queue.js
@@ -0,0 +1,199 @@
+var EventEmitter = require('events').EventEmitter;
+var util = require('util');
+
+var DEFAULT_TIMEOUT = 3000;
+var INIT_ID = 0;
+var EVENT_CLOSED = 'closed';
+var EVENT_DRAINED = 'drained';
+
+/**
+ * Instance a new queue
+ *
+ * @param {Number} timeout a global timeout for new queue
+ * @class
+ * @constructor
+ */
+var SeqQueue = function(timeout) {
+ EventEmitter.call(this);
+
+ if(timeout && timeout > 0) {
+ this.timeout = timeout;
+ } else {
+ this.timeout = DEFAULT_TIMEOUT;
+ }
+
+ this.status = SeqQueueManager.STATUS_IDLE;
+ this.curId = INIT_ID;
+ this.queue = [];
+};
+util.inherits(SeqQueue, EventEmitter);
+
+/**
+ * Add a task into queue.
+ *
+ * @param fn new request
+ * @param ontimeout callback when task timeout
+ * @param timeout timeout for current request. take the global timeout if this is invalid
+ * @returns true or false
+ */
+SeqQueue.prototype.push = function(fn, ontimeout, timeout) {
+ if(this.status !== SeqQueueManager.STATUS_IDLE && this.status !== SeqQueueManager.STATUS_BUSY) {
+ //ignore invalid status
+ return false;
+ }
+
+ if(typeof fn !== 'function') {
+ throw new Error('fn should be a function.');
+ }
+ this.queue.push({fn: fn, ontimeout: ontimeout, timeout: timeout});
+
+ if(this.status === SeqQueueManager.STATUS_IDLE) {
+ this.status = SeqQueueManager.STATUS_BUSY;
+ var self = this;
+ process.nextTick(function() {
+ self._next(self.curId);
+ });
+ }
+ return true;
+};
+
+/**
+ * Close queue
+ *
+ * @param {Boolean} force if true will close the queue immediately else will execute the rest task in queue
+ */
+SeqQueue.prototype.close = function(force) {
+ if(this.status !== SeqQueueManager.STATUS_IDLE && this.status !== SeqQueueManager.STATUS_BUSY) {
+ //ignore invalid status
+ return;
+ }
+
+ if(force) {
+ this.status = SeqQueueManager.STATUS_DRAINED;
+ if(this.timerId) {
+ clearTimeout(this.timerId);
+ this.timerId = undefined;
+ }
+ this.emit(EVENT_DRAINED);
+ } else {
+ this.status = SeqQueueManager.STATUS_CLOSED;
+ this.emit(EVENT_CLOSED);
+ }
+};
+
+/**
+ * Invoke next task
+ *
+ * @param {String|Number} tid last executed task id
+ * @api private
+ */
+SeqQueue.prototype._next = function(tid) {
+ if(tid !== this.curId || this.status !== SeqQueueManager.STATUS_BUSY && this.status !== SeqQueueManager.STATUS_CLOSED) {
+ //ignore invalid next call
+ return;
+ }
+
+ if(this.timerId) {
+ clearTimeout(this.timerId);
+ this.timerId = undefined;
+ }
+
+ var task = this.queue.shift();
+ if(!task) {
+ if(this.status === SeqQueueManager.STATUS_BUSY) {
+ this.status = SeqQueueManager.STATUS_IDLE;
+ this.curId++; //modify curId to invalidate timeout task
+ } else {
+ this.status = SeqQueueManager.STATUS_DRAINED;
+ this.emit(EVENT_DRAINED);
+ }
+ return;
+ }
+
+ var self = this;
+ task.id = ++this.curId;
+
+ var timeout = task.timeout > 0 ? task.timeout : this.timeout;
+ timeout = timeout > 0 ? timeout : DEFAULT_TIMEOUT;
+ this.timerId = setTimeout(function() {
+ process.nextTick(function() {
+ self._next(task.id);
+ });
+ self.emit('timeout', task);
+ if(task.ontimeout) {
+ task.ontimeout();
+ }
+ }, timeout);
+
+ try {
+ task.fn({
+ done: function() {
+ var res = task.id === self.curId;
+ process.nextTick(function() {
+ self._next(task.id);
+ });
+ return res;
+ }
+ });
+ } catch(err) {
+ self.emit('error', err, task);
+ process.nextTick(function() {
+ self._next(task.id);
+ });
+ }
+};
+
+/**
+ * Queue manager.
+ *
+ * @module
+ */
+var SeqQueueManager = module.exports;
+
+/**
+ * Queue status: idle, welcome new tasks
+ *
+ * @const
+ * @type {Number}
+ * @memberOf SeqQueueManager
+ */
+SeqQueueManager.STATUS_IDLE = 0;
+
+/**
+ * Queue status: busy, queue is working for some tasks now
+ *
+ * @const
+ * @type {Number}
+ * @memberOf SeqQueueManager
+ */
+SeqQueueManager.STATUS_BUSY = 1;
+
+/**
+ * Queue status: closed, queue has closed and would not receive task any more
+ * and is processing the remaining tasks now.
+ *
+ * @const
+ * @type {Number}
+ * @memberOf SeqQueueManager
+ */
+SeqQueueManager.STATUS_CLOSED = 2;
+
+/**
+ * Queue status: drained, queue is ready to be destroy
+ *
+ * @const
+ * @type {Number}
+ * @memberOf SeqQueueManager
+ */
+SeqQueueManager.STATUS_DRAINED = 3;
+
+/**
+ * Create Sequence queue
+ *
+ * @param {Number} timeout a global timeout for the new queue instance
+ * @return {Object} new queue instance
+ * @memberOf SeqQueueManager
+ */
+SeqQueueManager.createQueue = function(timeout) {
+ return new SeqQueue(timeout);
+}; \ No newline at end of file
diff --git a/node_modules/seq-queue/package.json b/node_modules/seq-queue/package.json
new file mode 100644
index 0000000..ec02f3a
--- /dev/null
+++ b/node_modules/seq-queue/package.json
@@ -0,0 +1,17 @@
+{
+ "name": "seq-queue",
+ "author": "changchang <changchang005@gmail.com>",
+ "version": "0.0.5",
+ "description": "A simple tool to keep requests to be executed in order.",
+ "homepage": "https://github.com/changchang/seq-queue",
+ "repository": {
+ "type": "git",
+ "url": "git@github.com:changchang/seq-queue.git"
+ },
+ "dependencies": {
+ },
+ "devDependencies": {
+ "mocha": ">=0.0.1",
+ "should": ">=0.0.1"
+ }
+} \ No newline at end of file
diff --git a/node_modules/seq-queue/test/seq-queue-test.js b/node_modules/seq-queue/test/seq-queue-test.js
new file mode 100644
index 0000000..d91724a
--- /dev/null
+++ b/node_modules/seq-queue/test/seq-queue-test.js
@@ -0,0 +1,307 @@
+var should = require('should');
+var SeqQueue = require('../lib/seq-queue');
+
+var timeout = 1000;
+
+describe('seq-queue', function() {
+
+ describe('#createQueue', function() {
+ it('should return a seq-queue instance with init properties', function() {
+ var queue = SeqQueue.createQueue(timeout);
+ should.exist(queue);
+ queue.should.have.property('timeout', timeout);
+ queue.should.have.property('status', SeqQueue.IDLE);
+ });
+ });
+
+ describe('#push' , function() {
+ it('should change the queue status from idle to busy and invoke the task at once when task finish when queue idle', function(done) {
+ var queue = SeqQueue.createQueue(timeout);
+ queue.should.have.property('status', SeqQueue.IDLE);
+ queue.push(function(task) {
+ should.exist(task);
+ task.done();
+ queue.should.have.property('status', SeqQueue.IDLE);
+ done();
+ });
+ queue.should.have.property('status', SeqQueue.BUSY);
+ });
+
+ it('should keep the status busy and keep the new task wait until the former tasks finish when queue busy', function(done) {
+ var queue = SeqQueue.createQueue(timeout);
+ var formerTaskFinished = false;
+ //add first task
+ queue.push(function(task) {
+ formerTaskFinished = true;
+ task.done();
+ });
+ queue.should.have.property('status', SeqQueue.BUSY);
+ //add second task
+ queue.push(function(task) {
+ formerTaskFinished.should.be.true;
+ queue.should.have.property('status', SeqQueue.BUSY);
+ task.done();
+ queue.should.have.property('status', SeqQueue.IDLE);
+ done();
+ });
+ queue.should.have.property('status', SeqQueue.BUSY);
+ });
+
+ it('should ok if the task call done() directly', function(done) {
+ var queue = SeqQueue.createQueue();
+ var taskCount = 0;
+ queue.push(function(task) {
+ taskCount++;
+ task.done();
+ });
+ queue.push(function(task) {
+ taskCount++;
+ task.done();
+ });
+ setTimeout(function() {
+ taskCount.should.equal(2);
+ done();
+ }, 500);
+ });
+ });
+
+ describe('#close', function() {
+ it('should not accept new request but should execute the rest task in queue when close gracefully', function(done) {
+ var queue = SeqQueue.createQueue(timeout);
+ var closedEventCount = 0;
+ var drainedEventCount = 0;
+ queue.on('closed', function() {
+ closedEventCount++;
+ });
+ queue.on('drained', function() {
+ drainedEventCount++;
+ });
+ var executedTaskCount = 0;
+ queue.push(function(task) {
+ executedTaskCount++;
+ task.done();
+ }).should.be.true;
+ queue.close(false);
+ queue.should.have.property('status', SeqQueue.CLOSED);
+
+ queue.push(function(task) {
+ // never should be executed
+ executedTaskCount++;
+ task.done();
+ }).should.be.false;
+
+ // wait all task finished
+ setTimeout(function() {
+ executedTaskCount.should.equal(1);
+ closedEventCount.should.equal(1);
+ drainedEventCount.should.equal(1);
+ done();
+ }, 1000);
+ });
+
+ it('should not execute any task and emit a drained event when close forcefully', function(done) {
+ var queue = SeqQueue.createQueue(timeout);
+ var drainedEventCount = 0;
+ queue.on('drained', function() {
+ drainedEventCount++;
+ });
+ var executedTaskCount = 0;
+ queue.push(function(task) {
+ //never should be executed
+ executedTaskCount++;
+ task.done();
+ }).should.be.true;
+ queue.close(true);
+ queue.should.have.property('status', SeqQueue.DRAINED);
+
+ // wait all task finished
+ setTimeout(function() {
+ executedTaskCount.should.equal(0);
+ drainedEventCount.should.equal(1);
+ done();
+ }, 1000);
+ });
+ });
+
+ describe('#timeout', function() {
+ it('should emit timeout event and execute the next task when a task timeout by default', function(done) {
+ var queue = SeqQueue.createQueue();
+ var executedTaskCount = 0;
+ var timeoutCount = 0;
+ var onTimeoutCount = 0;
+ //add timeout listener
+ queue.on('timeout', function(task) {
+ task.should.be.a('object');
+ task.fn.should.be.a('function');
+ timeoutCount++;
+ });
+
+ queue.push(function(task) {
+ executedTaskCount++;
+ //no task.done() invoke to cause a timeout
+ }, function() {
+ onTimeoutCount++;
+ }).should.be.true;
+
+ queue.push(function(task) {
+ executedTaskCount++;
+ task.done();
+ }).should.be.true;
+
+ setTimeout(function() {
+ //wait all task finish
+ executedTaskCount.should.be.equal(2);
+ timeoutCount.should.be.equal(1);
+ onTimeoutCount.should.be.equal(1);
+ done();
+ }, 4000); //default timeout is 3s
+ });
+
+ it('should return false when invoke task.done() if task has already timeout', function(done) {
+ var queue = SeqQueue.createQueue();
+ var executedTaskCount = 0;
+ var timeoutCount = 0;
+ var timeout = 1000;
+
+ //add timeout listener
+ queue.on('timeout', function(task) {
+ task.should.be.a('object');
+ task.fn.should.be.a('function');
+ timeoutCount++;
+ });
+
+ queue.push(function(task) {
+ executedTaskCount++;
+ task.done().should.be.true;
+ }).should.be.true;
+
+ queue.push(function(task) {
+ //sleep to make a timeout
+ setTimeout(function() {
+ executedTaskCount++;
+ task.done().should.be.false;
+ }, timeout + 1000);
+ }, null, timeout).should.be.true;
+
+ setTimeout(function() {
+ //wait all task finish
+ executedTaskCount.should.be.equal(2);
+ timeoutCount.should.be.equal(1);
+ done();
+ }, 4000);
+ });
+
+ it('should never timeout after close forcefully', function(done) {
+ var queue = SeqQueue.createQueue(timeout);
+ var timeoutCount = 0;
+ //add timeout listener
+ queue.on('timeout', function(task) {
+ //should never enter here
+ timeoutCount++;
+ });
+
+ queue.push(function(task) {
+ //no task.done() invoke to cause a timeout
+ }).should.be.true;
+
+ queue.close(true);
+
+ setTimeout(function() {
+ //wait all task finish
+ timeoutCount.should.be.equal(0);
+ done();
+ }, timeout * 2);
+ });
+
+ it('should use the global timeout value by default', function(done) {
+ var globalTimeout = timeout + 100;
+ var queue = SeqQueue.createQueue(globalTimeout);
+ //add timeout listener
+ queue.on('timeout', function(task) {
+ (Date.now() - start).should.not.be.below(globalTimeout);
+ done();
+ });
+
+ queue.push(function(task) {
+ //no task.done() invoke to cause a timeout
+ }).should.be.true;
+ var start = Date.now();
+ });
+
+ it('should use the timeout value in #push if it was assigned', function(done) {
+ var localTimeout = timeout / 2;
+ var queue = SeqQueue.createQueue(timeout);
+ //add timeout listener
+ queue.on('timeout', function(task) {
+ var diff = Date.now() - start;
+ diff.should.not.be.below(localTimeout);
+ diff.should.not.be.above(timeout);
+ done();
+ });
+
+ queue.push(function(task) {
+ //no task.done() invoke to cause a timeout
+ }, null, localTimeout).should.be.true;
+ var start = Date.now();
+ });
+ });
+
+ describe('#error', function() {
+ it('should emit an error event and invoke next task when a task throws an event', function(done) {
+ var queue = SeqQueue.createQueue();
+ var errorCount = 0;
+ var taskCount = 0;
+ //add timeout listener
+ queue.on('error', function(err, task) {
+ errorCount++;
+ should.exist(err);
+ should.exist(task);
+ });
+
+ queue.push(function(task) {
+ taskCount++;
+ throw new Error('some error');
+ }).should.be.true;
+
+ queue.push(function(task) {
+ taskCount++;
+ task.done();
+ });
+
+ setTimeout(function() {
+ taskCount.should.equal(2);
+ errorCount.should.equal(1);
+ done();
+ }, 500);
+ });
+
+ it('should be ok when task throw a error after done was invoked', function(done) {
+ var queue = SeqQueue.createQueue();
+ var errorCount = 0;
+ var taskCount = 0;
+ //add timeout listener
+ queue.on('error', function(err, task) {
+ errorCount++;
+ should.exist(err);
+ should.exist(task);
+ });
+
+ queue.push(function(task) {
+ taskCount++;
+ task.done();
+ throw new Error('some error');
+ }).should.be.true;
+
+ queue.push(function(task) {
+ taskCount++;
+ task.done();
+ });
+
+ setTimeout(function() {
+ taskCount.should.equal(2);
+ errorCount.should.equal(1);
+ done();
+ }, 500);
+ });
+ });
+}); \ No newline at end of file