diff --git a/src/Scheduler.ts b/src/Scheduler.ts index a9767cc..f6ec515 100644 --- a/src/Scheduler.ts +++ b/src/Scheduler.ts @@ -28,8 +28,8 @@ export class Scheduler { private scheduleUniqTask(seconds: number, name: string, args: Args = {}) { const taskScheduler = () => { - if (!this.taskQueue.hasNamed(name)) { - this.taskQueue.push(name, args, timestamp() + Math.min(seconds, 5 * 60)); + if (!this.taskQueue.has(t => t.name === name)) { + this.scheduleTask(name, args, timestamp() + Math.min(seconds, 5 * 60)); } }; taskScheduler(); @@ -48,23 +48,23 @@ export class Scheduler { return this.actionQueue.pop(); } - scheduleTask(name: string, args: Args): void { - this.logger.log('PUSH TASK', name, args); + scheduleTask(name: string, args: Args, ts?: number | undefined): void { + this.logger.log('PUSH TASK', name, args, ts); const villageId = args.villageId; if (isBuildingTask(name)) { - this.taskQueue.insertAfterLast( + const insertedTs = calculateTimeToPushAfter( + this.taskQueue.seeItems(), t => isBuildingTask(t.name) && sameVillage(villageId, t.args), - name, - args, - timestamp() + ts ); + this.taskQueue.push(name, args, insertedTs); } else { - this.taskQueue.push(name, args, timestamp()); + this.taskQueue.push(name, args, ts || timestamp()); } } completeTask(id: TaskId) { - this.taskQueue.complete(id); + this.taskQueue.remove(id); this.actionQueue.clear(); } @@ -74,13 +74,16 @@ export class Scheduler { } postponeTask(id: TaskId, deltaTs: number) { - this.taskQueue.postpone(id, timestamp() + deltaTs); + this.taskQueue.modify( + t => t.id === id, + t => withTime(t, timestamp() + deltaTs) + ); } postponeBuildingsInVillage(villageId: number, seconds: number) { this.taskQueue.modify( t => isBuildingTask(t.name) && sameVillage(villageId, t.args), - t => t.withTime(timestamp() + seconds) + t => withTime(t, timestamp() + seconds) ); } @@ -100,3 +103,29 @@ function isBuildingTask(taskName: string) { function sameVillage(villageId: number | undefined, args: Args) { return villageId !== undefined && args.villageId === villageId; } + +export function withTime(task: Task, ts: number): Task { + return new Task(task.id, ts, task.name, task.args); +} + +function calculateTimeToPushAfter(tasks: TaskList, predicate: (t: Task) => boolean, ts: number | undefined): number { + const normalizedTs = ts || timestamp(); + const queuedTaskIndex = findLastIndex(tasks, predicate); + if (queuedTaskIndex === undefined) { + return normalizedTs; + } + const queuedTask = tasks[queuedTaskIndex]; + return Math.max(normalizedTs, queuedTask.ts + 1); +} + +function findLastIndex(tasks: TaskList, predicate: (t: Task) => boolean): number | undefined { + const count = tasks.length; + const indexInReversed = tasks + .slice() + .reverse() + .findIndex(predicate); + if (indexInReversed < 0) { + return undefined; + } + return count - 1 - indexInReversed; +} diff --git a/src/Storage/TaskQueue.ts b/src/Storage/TaskQueue.ts index 1625421..cf65560 100644 --- a/src/Storage/TaskQueue.ts +++ b/src/Storage/TaskQueue.ts @@ -23,10 +23,6 @@ export class Task { this.name = name; this.args = args; } - - withTime(ts: number): Task { - return new Task(this.id, ts, this.name, this.args); - } } export type TaskList = Array; @@ -50,15 +46,6 @@ export class TaskQueue { return task; } - insertAfterLast(predicate: (t: Task) => boolean, name: string, args: Args, ts: number): Task { - const id = uniqTaskId(); - const task = new Task(id, ts, name, args); - this.logger.log('INSERT AFTER TASK', id, ts, name, args); - const items = insertTaskAfter(task, this.getItems(), predicate); - this.flushItems(items); - return task; - } - get(ts: number): Task | undefined { const readyItems = this.getItems().filter(t => t.ts <= ts); if (readyItems.length === 0) { @@ -72,30 +59,12 @@ export class TaskQueue { return matched.length > 0; } - hasNamed(name: string): boolean { - return this.has(t => t.name === name); - } - modify(predicate: (t: Task) => boolean, modifier: (t: Task) => Task) { const [matched, other] = this.split(predicate); const modified = matched.map(modifier); this.flushItems(modified.concat(other)); } - complete(id: TaskId) { - const [_, items] = this.shiftTask(id); - this.flushItems(items); - } - - postpone(id: TaskId, newTs: number) { - const [task, items] = this.shiftTask(id); - if (task) { - this.logger.log('POSTPONE', task); - items.push(task.withTime(newTs)); - } - this.flushItems(items); - } - remove(id: TaskId) { const [_, items] = this.shiftTask(id); this.flushItems(items); @@ -142,27 +111,3 @@ export class TaskQueue { this.storage.set(QUEUE_NAME, normalized); } } - -function insertTaskAfter(task: Task, tasks: TaskList, predicate: (t: Task) => boolean): TaskList { - const queuedTaskIndex = findLastIndex(tasks, predicate); - if (queuedTaskIndex === undefined) { - tasks.push(task); - return tasks; - } - const queuedTask = tasks[queuedTaskIndex]; - let insertedTask = task.withTime(Math.max(task.ts, queuedTask.ts + 1)); - tasks.splice(queuedTaskIndex, 0, insertedTask); - return tasks; -} - -function findLastIndex(tasks: TaskList, predicate: (t: Task) => boolean): number | undefined { - const count = tasks.length; - const indexInReversed = tasks - .slice() - .reverse() - .findIndex(predicate); - if (indexInReversed < 0) { - return undefined; - } - return count - 1 - indexInReversed; -}