diff --git a/package-lock.json b/package-lock.json index 23b2a9b..e1615f1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "ethernet-ip", - "version": "1.0.4", + "version": "1.1.4", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -4330,6 +4330,11 @@ "string-width": "2.1.1" } }, + "task-easy": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/task-easy/-/task-easy-0.2.0.tgz", + "integrity": "sha512-vjxMnoxo1zAQSguriduZXt5kOejTcGnmNuWbK2yyJtxO6KzaxR4JU8gXfZTXD6uBCnh2RWZdUcHzvHkQ5e04Ow==" + }, "test-exclude": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-4.1.1.tgz", diff --git a/package.json b/package.json index 7d22931..2c57221 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ethernet-ip", - "version": "1.1.4", + "version": "1.1.5", "description": "A simple node interface for Ethernet/IP.", "main": "./src/index.js", "scripts": { @@ -28,7 +28,8 @@ "controller" ], "dependencies": { - "dateformat": "^3.0.3" + "dateformat": "^3.0.3", + "task-easy": "^0.2.0" }, "devDependencies": { "colors": "^1.2.0", diff --git a/src/controller/index.js b/src/controller/index.js index f7a9416..60bde1a 100644 --- a/src/controller/index.js +++ b/src/controller/index.js @@ -1,7 +1,8 @@ const { ENIP, CIP } = require("../enip"); const dateFormat = require("dateformat"); const TagGroup = require("../tag-group"); -const { delay, promiseTimeout, TaskQueue } = require("../utilities"); +const { delay, promiseTimeout } = require("../utilities"); +const Queue = require("task-easy"); const compare = (obj1, obj2) => { if (obj1.priority > obj2.priority) return true; @@ -36,9 +37,9 @@ class Controller extends ENIP { }; this.workers = { - read: new TaskQueue(compare), - write: new TaskQueue(compare), - group: new TaskQueue(compare) + read: new Queue(compare), + write: new Queue(compare), + group: new Queue(compare) }; } diff --git a/src/utilities/__snapshots__/utilities.spec.js.snap b/src/utilities/__snapshots__/utilities.spec.js.snap deleted file mode 100644 index e782830..0000000 --- a/src/utilities/__snapshots__/utilities.spec.js.snap +++ /dev/null @@ -1,281 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Utilites Task Queue Class Private Methods Build Heap Works Correctly 1`] = ` -Array [ - Object { - "args": Array [ - 1400, - ], - "priority_obj": Object { - "value": 14, - }, - "task": [Function], - }, - Object { - "args": Array [ - 1000, - ], - "priority_obj": Object { - "value": 10, - }, - "task": [Function], - }, - Object { - "args": Array [ - 1300, - ], - "priority_obj": Object { - "value": 13, - }, - "task": [Function], - }, - Object { - "args": Array [ - 800, - ], - "priority_obj": Object { - "value": 8, - }, - "task": [Function], - }, - Object { - "args": Array [ - 900, - ], - "priority_obj": Object { - "value": 9, - }, - "task": [Function], - }, - Object { - "args": Array [ - 1200, - ], - "priority_obj": Object { - "value": 12, - }, - "task": [Function], - }, - Object { - "args": Array [ - 600, - ], - "priority_obj": Object { - "value": 6, - }, - "task": [Function], - }, - Object { - "args": Array [ - 700, - ], - "priority_obj": Object { - "value": 7, - }, - "task": [Function], - }, - Object { - "args": Array [ - 300, - ], - "priority_obj": Object { - "value": 3, - }, - "task": [Function], - }, - Object { - "args": Array [ - 100, - ], - "priority_obj": Object { - "value": 1, - }, - "task": [Function], - }, - Object { - "args": Array [ - 400, - ], - "priority_obj": Object { - "value": 4, - }, - "task": [Function], - }, - Object { - "args": Array [ - 1100, - ], - "priority_obj": Object { - "value": 11, - }, - "task": [Function], - }, - Object { - "args": Array [ - 500, - ], - "priority_obj": Object { - "value": 5, - }, - "task": [Function], - }, - Object { - "args": Array [ - 200, - ], - "priority_obj": Object { - "value": 2, - }, - "task": [Function], - }, - Object { - "args": Array [ - 0, - ], - "priority_obj": Object { - "value": 0, - }, - "task": [Function], - }, -] -`; - -exports[`Utilites Task Queue Class Private Methods Reorder Method Produces Correct Output 1`] = ` -Array [ - Object { - "args": Array [ - 200, - ], - "priority_obj": Object { - "value": 2, - }, - "task": [Function], - }, - Object { - "args": Array [ - 100, - ], - "priority_obj": Object { - "value": 1, - }, - "task": [Function], - }, - Object { - "args": Array [ - 600, - ], - "priority_obj": Object { - "value": 6, - }, - "task": [Function], - }, - Object { - "args": Array [ - 300, - ], - "priority_obj": Object { - "value": 3, - }, - "task": [Function], - }, - Object { - "args": Array [ - 400, - ], - "priority_obj": Object { - "value": 4, - }, - "task": [Function], - }, - Object { - "args": Array [ - 500, - ], - "priority_obj": Object { - "value": 5, - }, - "task": [Function], - }, - Object { - "args": Array [ - 1400, - ], - "priority_obj": Object { - "value": 14, - }, - "task": [Function], - }, - Object { - "args": Array [ - 700, - ], - "priority_obj": Object { - "value": 7, - }, - "task": [Function], - }, - Object { - "args": Array [ - 800, - ], - "priority_obj": Object { - "value": 8, - }, - "task": [Function], - }, - Object { - "args": Array [ - 900, - ], - "priority_obj": Object { - "value": 9, - }, - "task": [Function], - }, - Object { - "args": Array [ - 1000, - ], - "priority_obj": Object { - "value": 10, - }, - "task": [Function], - }, - Object { - "args": Array [ - 1100, - ], - "priority_obj": Object { - "value": 11, - }, - "task": [Function], - }, - Object { - "args": Array [ - 1200, - ], - "priority_obj": Object { - "value": 12, - }, - "task": [Function], - }, - Object { - "args": Array [ - 1300, - ], - "priority_obj": Object { - "value": 13, - }, - "task": [Function], - }, - Object { - "args": Array [ - 0, - ], - "priority_obj": Object { - "value": 0, - }, - "task": [Function], - }, -] -`; diff --git a/src/utilities/index.js b/src/utilities/index.js index dc648a4..2eb9adb 100644 --- a/src/utilities/index.js +++ b/src/utilities/index.js @@ -22,178 +22,4 @@ const promiseTimeout = (promise, ms, error = new Error("ASYNC Function Call Time */ const delay = ms => new Promise(resolve => setTimeout(resolve, ms)); -/** - * A simple Job Scheduler/ Task Runner class - * - * @param {function} compare_func - Compares Priority Objects - * @param {number} - * @class JobQueue - */ -class TaskQueue { - constructor(compare_func, max_queue_size = 100) { - this.tasks = []; - this.taskRunning = false; - this.max = max_queue_size; - - if (typeof compare_func !== "function") - throw new Error( - `JobQueue Comparison Function must be of Type instead got ${typeof compare_func}` - ); - - if (typeof max_queue_size !== "number") - throw new Error( - `JobQueue Max Queue Size must be of Type instead got ${typeof number}` - ); - - this.compare = compare_func; - } - - /** - * Schedules a new "Task" to be Performed - * - * @param {function} task - task to schedule - * @param {Array} args - array of arguments to pass to task - * @param {object} priority_obj - object that will be passed to comparison handler provided in the constructor - * @returns - * @memberof TaskQueue - */ - schedule(task, args, priority_obj) { - if (typeof task !== "function") - throw new Error(`Scheduler Task must be of Type instead got ${typeof task}`); - if (!Array.isArray(args)) - throw new Error(`Scheduler args must be of Type instead got ${typeof args}`); - if (typeof priority_obj !== "object") - throw new Error( - `Scheduler Task must be of Type instead got ${typeof priority_obj}` - ); - - // return Promise to Caller - return new Promise((resolve, reject) => { - if (this.tasks.length > this.max) { - reject(new Error("Task Queue Exceeded Max Queue Size!!!")); - } else { - // Push Task to Queue - if (this.tasks.length === 0) { - this.tasks.push({ task, args, priority_obj, resolve, reject }); - this._next(); - } else { - this.tasks.push({ task, args, priority_obj, resolve, reject }); - } - } - }); - } - - /** - * Gets Parent Node Index - * - * @param {number} index - * @returns {number} - * @memberof TaskQueue - */ - _getParent(index) { - return Math.trunc((index - 1) / 2); - } - - /** - * Gets Left Child Node Index - * - * @param {number} index - * @returns {number} - * @memberof TaskQueue - */ - _getLNode(index) { - return index * 2 + 1; - } - - /** - * Gets Right Child Node Index - * - * @param {number} index - * @returns - * @memberof TaskQueue - */ - _getRNode(index) { - return index * 2 + 2; - } - - /** - * Recursively Reorders from Seed Index Based on Outcome of Comparison Function - * - * @param {number} index - * @memberof TaskQueue - */ - _reorder(index) { - const { compare } = this; - const size = this.tasks.length; - - const l = this._getLNode(index); - const r = this._getRNode(index); - - let swap = index; - - if (l < size && compare(this.tasks[l].priority_obj, this.tasks[swap].priority_obj)) - swap = l; - if (r < size && compare(this.tasks[r].priority_obj, this.tasks[swap].priority_obj)) - swap = r; - - if (swap !== index) { - const temp = this.tasks[index]; - this.tasks[index] = this.tasks[swap]; - this.tasks[swap] = temp; - this._reorder(swap); - } - } - - /** - * Organized Queue based on Priority - * - * @memberof TaskQueue - */ - _orderQueue() { - const size = this.tasks.length; - const start = Math.trunc((size - 2) / 2); - - for (let i = start; i >= 0; i--) { - this._reorder(i); - } - } - - /** - * Executes Highest Priority Task - * - * @memberof TaskQueue - */ - _runTask() { - this._orderQueue(); - - const job = this.tasks.shift(); - const { task, args, resolve, reject } = job; - - this.taskRunning = true; - - task(...args) - .then((...args) => { - resolve(...args); - this.taskRunning = false; - this._next(); - }) - .catch((...args) => { - reject(...args); - this.taskRunning = false; - this._next(); - }); - } - - /** - * Executes Next Task in Queue if One Exists and One is Currently Running - * - * @memberof TaskQueue - */ - _next() { - if (this.tasks.length !== 0 && this.taskRunning === false) { - this._runTask(); - } - } -} - -module.exports = { promiseTimeout, delay, TaskQueue }; +module.exports = { promiseTimeout, delay }; diff --git a/src/utilities/utilities.spec.js b/src/utilities/utilities.spec.js index 2745f79..c48c925 100644 --- a/src/utilities/utilities.spec.js +++ b/src/utilities/utilities.spec.js @@ -1,4 +1,4 @@ -const { promiseTimeout, delay, TaskQueue } = require("./index"); +const { promiseTimeout, delay } = require("./index"); describe("Utilites", () => { describe("Promise Timeout Utility", () => { @@ -44,106 +44,4 @@ describe("Utilites", () => { await expect(fn(50)).resolves.toBeUndefined(); }); }); - - describe("Task Queue Class", () => { - describe("New Instance", () => { - it("Rejects Improper Constructor Arguments", () => { - const fn = arg => () => new TaskQueue(arg); - - expect(fn()).toThrow(); - expect(fn("hello")).toThrow(); - expect(fn({ a: 6 })).toThrow(); - expect(fn(() => console.log("hello"))).not.toThrow(); - }); - }); - - describe("Private Methods", () => { - let compare; - let arr; - let q; - - beforeEach(() => { - arr = []; - compare = (obj1, obj2) => obj1.value >= obj2.value; - - for (let i = 0; i < 15; i++) { - arr.push({ - task: delay, - args: [100 * i], - priority_obj: { value: i } - }); - } - - q = new TaskQueue(compare); - q.tasks = arr; - }); - - it("Primitive Heap Methods Generate Correct Values", () => { - expect(q._getParent(5)).toEqual(2); - expect(q._getParent(6)).toEqual(2); - - expect(q._getLNode(5)).toEqual(11); - expect(q._getLNode(25)).toEqual(51); - - expect(q._getRNode(5)).toEqual(12); - expect(q._getRNode(25)).toEqual(52); - }); - - it("Reorder Method Produces Correct Output", () => { - q._reorder(0); - expect(q.tasks).toMatchSnapshot(); - }); - - it("Build Heap Works Correctly", () => { - q._orderQueue(); - expect(q.tasks).toMatchSnapshot(); - }); - - it("Runs Tasks on Push", async () => { - const delayReturn = ms => - new Promise((resolve, reject) => { - if (typeof ms !== "number") reject("Bad Input"); - else - setTimeout(() => { - resolve(ms); - }, ms); - }); - - const q = new TaskQueue(compare); - const p1 = q.schedule(delayReturn, [50], { value: 1 }); - const p2 = q.schedule(delayReturn, [60], { value: 1 }); - const p3 = q.schedule(delayReturn, [70], { value: 1 }); - - await expect(p1).resolves.toBe(50); - await expect(p2).resolves.toBe(60); - await expect(p3).resolves.toBe(70); - }); - - it("Runs Tasks on Priority", async () => { - const delayReturn = ms => - new Promise((resolve, reject) => { - if (typeof ms !== "number") reject("Bad Input"); - else - setTimeout(() => { - resolve(ms); - }, ms); - }); - - const q = new TaskQueue(compare); - const p1 = q.schedule(delayReturn, [100], { value: 1, id: 1 }); - const p2 = q.schedule(delayReturn, [110], { value: 1, id: 2 }); - const p3 = q.schedule(delayReturn, [120], { value: 2, id: 3 }); - const p4 = q.schedule(delayReturn, [130], { value: 3, id: 4 }); - const p5 = q.schedule(delayReturn, [140], { value: 1, id: 5 }); - const p6 = q.schedule(delayReturn, ["hello"], { value: 0, id: 6 }); - - await expect(p1).resolves.toBe(100); - await expect(p2).resolves.toBe(110); - await expect(p3).resolves.toBe(120); - await expect(p4).resolves.toBe(130); - await expect(p5).resolves.toBe(140); - await expect(p6).rejects.toBe("Bad Input"); - }); - }); - }); });