'use strict'; const assureArray = require("assure-array"); const createEventEmitter = require("create-event-emitter"); const uuid = require("uuid"); const findAndSplice = require("../find-and-splice"); module.exports = function createTaskTracker() { let tasks = []; return createEventEmitter({ addTask: function addTask(name, indicator, userIds, roleIds, options) { let mergedOptions = Object.assign({ removeWhenDone: true }, options); let indicatorType; if (typeof indicator.completed === "function" && typeof indicator.finish === "function") { indicatorType = "are-we-there-yet"; } else if (typeof indicator.await === "function" && typeof indicator.report === "function") { indicatorType = "progress-indicator"; } else { throw new Error("Unrecognized indicator type"); } let task = createEventEmitter({ id: uuid.v4(), name: name, started: Date.now(), userIds: assureArray(userIds), roleIds: assureArray(roleIds), indicator: indicator, type: indicatorType, progress: 0, lastOperation: null, lastUpdated: null }); let reportChange = () => { this.emit("progress", task, task.progress, task.lastOperation); task.emit("progress", task.progress, task.lastOperation); } let reportCompleted = () => { this.emit("completed", task); task.emit("completed"); if (mergedOptions.removeWhenDone) { this.removeTask(task); } } tasks.push(task); if (indicatorType === "are-we-there-yet") { indicator.on("change", (name, completed, tracker) => { task.progress = completed; task.lastOperation = name; task.lastUpdated = Date.now(); reportChange(); if (completed === 1) { reportCompleted(); } }); } else if (indicatorType === "progress-indicator") { indicator.on("progress", (progress, description, completed, total) => { task.progress = progress; task.lastOperation = description; task.lastUpdated = Date.now(); reportChange(); }); indicator.on("completed", () => { reportCompleted(); }); } this.emit("newTask", task); assureArray(userIds).forEach((userId) => { this.emit(`newTask:user:${userId}`, task); }); assureArray(roleIds).forEach((roleId) => { this.emit(`newTask:role:${roleId}`, task); }); return task; }, removeTask: function removeTask(task) { // FIXME: Do we need to remove event handlers to prevent a memory leak here? findAndSplice(tasks, task); }, byUser: function getTasksByUser(userId) { return tasks.filter((task) => task.userIds.includes(userId)); }, byRole: function getTasksByRole(roleId) { return tasks.filter((task) => task.roleIds.includes(roleId)) }, all: function getAllTasks() { return tasks; } }); }