Add ability to postpone all building tasks when queue is full

This commit is contained in:
Anton Vakhrushev 2020-04-02 19:59:57 +03:00
parent 163375f62d
commit 711c8a414b
6 changed files with 49 additions and 14 deletions

View File

@ -1,7 +1,7 @@
import ActionController from './ActionController'; import ActionController from './ActionController';
import { Args } from '../Common'; import { Args } from '../Common';
import { Task } from '../Storage/TaskQueue'; import { Task } from '../Storage/TaskQueue';
import { TryLaterError } from '../Errors'; import { BuildingQueueFullError } from '../Errors';
export default class CheckBuildingRemainingTimeAction extends ActionController { export default class CheckBuildingRemainingTimeAction extends ActionController {
static NAME = 'check_building_remaining_time'; static NAME = 'check_building_remaining_time';
@ -11,7 +11,7 @@ export default class CheckBuildingRemainingTimeAction extends ActionController {
if (timer.length === 1) { if (timer.length === 1) {
const remainingSeconds = Number(timer.attr('value')); const remainingSeconds = Number(timer.attr('value'));
if (remainingSeconds > 0) { if (remainingSeconds > 0) {
throw new TryLaterError( throw new BuildingQueueFullError(
remainingSeconds + 1, remainingSeconds + 1,
'Building queue is full' 'Building queue is full'
); );

View File

@ -1,5 +1,5 @@
import * as URLParse from 'url-parse'; import * as URLParse from 'url-parse';
import { markPage, sleepShort, uniqId } from './utils'; import { markPage, uniqId, waitForLoad } from './utils';
import Scheduler from './Scheduler'; import Scheduler from './Scheduler';
import UpgradeBuildingTask from './Task/UpgradeBuildingTask'; import UpgradeBuildingTask from './Task/UpgradeBuildingTask';
import { Command } from './Common'; import { Command } from './Common';
@ -15,8 +15,7 @@ export default class Dashboard {
} }
async run() { async run() {
await this.load(); await waitForLoad();
await sleepShort();
const p = new URLParse(window.location.href, true); const p = new URLParse(window.location.href, true);
this.log('PARSED LOCATION', p); this.log('PARSED LOCATION', p);
@ -77,10 +76,6 @@ export default class Dashboard {
}); });
} }
private async load() {
return new Promise(resolve => jQuery(resolve));
}
private log(...args) { private log(...args) {
console.log('SCHEDULER:', ...args); console.log('SCHEDULER:', ...args);
} }

View File

@ -10,3 +10,14 @@ export class TryLaterError extends Error {
Object.setPrototypeOf(this, TryLaterError.prototype); Object.setPrototypeOf(this, TryLaterError.prototype);
} }
} }
export class BuildingQueueFullError extends Error {
readonly seconds: number;
readonly id: TaskId;
constructor(seconds: number, id: TaskId, msg: string = '') {
super(msg);
this.id = id;
this.seconds = seconds;
Object.setPrototypeOf(this, TryLaterError.prototype);
}
}

View File

@ -1,7 +1,7 @@
import { markPage, sleepShort, timestamp } from './utils'; import { markPage, sleepShort, timestamp } from './utils';
import UpgradeBuildingTask from './Task/UpgradeBuildingTask'; import UpgradeBuildingTask from './Task/UpgradeBuildingTask';
import UpgradeBuildingAction from './Action/UpgradeBuildingAction'; import UpgradeBuildingAction from './Action/UpgradeBuildingAction';
import { TryLaterError } from './Errors'; import { BuildingQueueFullError, TryLaterError } from './Errors';
import { TaskQueue, TaskList, Task, TaskId } from './Storage/TaskQueue'; import { TaskQueue, TaskList, Task, TaskId } from './Storage/TaskQueue';
import ActionQueue from './Storage/ActionQueue'; import ActionQueue from './Storage/ActionQueue';
import { Args, Command } from './Common'; import { Args, Command } from './Common';
@ -143,6 +143,14 @@ export default class Scheduler {
this.actionQueue.clear(); this.actionQueue.clear();
this.taskQueue.postpone(task.id, timestamp() + e.seconds); this.taskQueue.postpone(task.id, timestamp() + e.seconds);
} }
if (e instanceof BuildingQueueFullError) {
console.warn('BUILDING QUEUE FULL, TRY ALL AFTER', e.seconds);
this.actionQueue.clear();
this.taskQueue.modify(
t => t.cmd.name === UpgradeBuildingTask.NAME,
t => t.withTime(timestamp() + e.seconds)
);
}
} }
} }

View File

@ -49,6 +49,12 @@ export class TaskQueue {
return readyItems[0]; return readyItems[0];
} }
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) { complete(id: TaskId) {
const [_, items] = this.shiftTask(id); const [_, items] = this.shiftTask(id);
this.flushItems(items); this.flushItems(items);
@ -68,10 +74,21 @@ export class TaskQueue {
} }
private shiftTask(id: TaskId): [Task | undefined, TaskList] { private shiftTask(id: TaskId): [Task | undefined, TaskList] {
const items = this.getItems(); const [a, b] = this.split(t => t.id === id);
const task = items.find(t => t.id === id); return [a.shift(), b];
const tail = items.filter(t => t.id !== id); }
return [task, tail];
private split(predicate: (t: Task) => boolean): [TaskList, TaskList] {
const matched: TaskList = [];
const other: TaskList = [];
this.getItems().forEach(t => {
if (predicate(t)) {
matched.push(t);
} else {
other.push(t);
}
});
return [matched, other];
} }
private getItems(): TaskList { private getItems(): TaskList {

View File

@ -18,6 +18,10 @@ export async function sleepLong() {
return await sleep(ms); return await sleep(ms);
} }
export async function waitForLoad() {
return new Promise(resolve => jQuery(resolve));
}
export function uniqId(): string { export function uniqId(): string {
return 'id' + smallIdGenerator(); return 'id' + smallIdGenerator();
} }