Clear task queue logic
This commit is contained in:
		| @@ -28,8 +28,8 @@ export class Scheduler { | |||||||
|  |  | ||||||
|     private scheduleUniqTask(seconds: number, name: string, args: Args = {}) { |     private scheduleUniqTask(seconds: number, name: string, args: Args = {}) { | ||||||
|         const taskScheduler = () => { |         const taskScheduler = () => { | ||||||
|             if (!this.taskQueue.hasNamed(name)) { |             if (!this.taskQueue.has(t => t.name === name)) { | ||||||
|                 this.taskQueue.push(name, args, timestamp() + Math.min(seconds, 5 * 60)); |                 this.scheduleTask(name, args, timestamp() + Math.min(seconds, 5 * 60)); | ||||||
|             } |             } | ||||||
|         }; |         }; | ||||||
|         taskScheduler(); |         taskScheduler(); | ||||||
| @@ -48,23 +48,23 @@ export class Scheduler { | |||||||
|         return this.actionQueue.pop(); |         return this.actionQueue.pop(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     scheduleTask(name: string, args: Args): void { |     scheduleTask(name: string, args: Args, ts?: number | undefined): void { | ||||||
|         this.logger.log('PUSH TASK', name, args); |         this.logger.log('PUSH TASK', name, args, ts); | ||||||
|         const villageId = args.villageId; |         const villageId = args.villageId; | ||||||
|         if (isBuildingTask(name)) { |         if (isBuildingTask(name)) { | ||||||
|             this.taskQueue.insertAfterLast( |             const insertedTs = calculateTimeToPushAfter( | ||||||
|  |                 this.taskQueue.seeItems(), | ||||||
|                 t => isBuildingTask(t.name) && sameVillage(villageId, t.args), |                 t => isBuildingTask(t.name) && sameVillage(villageId, t.args), | ||||||
|                 name, |                 ts | ||||||
|                 args, |  | ||||||
|                 timestamp() |  | ||||||
|             ); |             ); | ||||||
|  |             this.taskQueue.push(name, args, insertedTs); | ||||||
|         } else { |         } else { | ||||||
|             this.taskQueue.push(name, args, timestamp()); |             this.taskQueue.push(name, args, ts || timestamp()); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     completeTask(id: TaskId) { |     completeTask(id: TaskId) { | ||||||
|         this.taskQueue.complete(id); |         this.taskQueue.remove(id); | ||||||
|         this.actionQueue.clear(); |         this.actionQueue.clear(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -74,13 +74,16 @@ export class Scheduler { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     postponeTask(id: TaskId, deltaTs: number) { |     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) { |     postponeBuildingsInVillage(villageId: number, seconds: number) { | ||||||
|         this.taskQueue.modify( |         this.taskQueue.modify( | ||||||
|             t => isBuildingTask(t.name) && sameVillage(villageId, t.args), |             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) { | function sameVillage(villageId: number | undefined, args: Args) { | ||||||
|     return villageId !== undefined && args.villageId === villageId; |     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; | ||||||
|  | } | ||||||
|   | |||||||
| @@ -23,10 +23,6 @@ export class Task { | |||||||
|         this.name = name; |         this.name = name; | ||||||
|         this.args = args; |         this.args = args; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     withTime(ts: number): Task { |  | ||||||
|         return new Task(this.id, ts, this.name, this.args); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  |  | ||||||
| export type TaskList = Array<Task>; | export type TaskList = Array<Task>; | ||||||
| @@ -50,15 +46,6 @@ export class TaskQueue { | |||||||
|         return task; |         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 { |     get(ts: number): Task | undefined { | ||||||
|         const readyItems = this.getItems().filter(t => t.ts <= ts); |         const readyItems = this.getItems().filter(t => t.ts <= ts); | ||||||
|         if (readyItems.length === 0) { |         if (readyItems.length === 0) { | ||||||
| @@ -72,30 +59,12 @@ export class TaskQueue { | |||||||
|         return matched.length > 0; |         return matched.length > 0; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     hasNamed(name: string): boolean { |  | ||||||
|         return this.has(t => t.name === name); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     modify(predicate: (t: Task) => boolean, modifier: (t: Task) => Task) { |     modify(predicate: (t: Task) => boolean, modifier: (t: Task) => Task) { | ||||||
|         const [matched, other] = this.split(predicate); |         const [matched, other] = this.split(predicate); | ||||||
|         const modified = matched.map(modifier); |         const modified = matched.map(modifier); | ||||||
|         this.flushItems(modified.concat(other)); |         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) { |     remove(id: TaskId) { | ||||||
|         const [_, items] = this.shiftTask(id); |         const [_, items] = this.shiftTask(id); | ||||||
|         this.flushItems(items); |         this.flushItems(items); | ||||||
| @@ -142,27 +111,3 @@ export class TaskQueue { | |||||||
|         this.storage.set(QUEUE_NAME, normalized); |         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; |  | ||||||
| } |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user