Optimize postpone error handler

This commit is contained in:
Anton Vakhrushev 2020-04-19 11:53:18 +03:00
parent 84ac56d052
commit 24ceb04307
7 changed files with 49 additions and 55 deletions

View File

@ -1,7 +1,9 @@
import { Args } from '../Command'; import { Args } from '../Command';
import { Task } from '../Queue/TaskQueue'; import { Task } from '../Queue/TaskQueue';
import { DataStorage } from '../DataStorage';
import { Scheduler } from '../Scheduler'; import { Scheduler } from '../Scheduler';
import { ActionError, TryLaterError } from '../Errors';
import { grabActiveVillageId } from '../Page/VillageBlock';
import { aroundMinutes } from '../utils';
const actionMap: { [name: string]: Function | undefined } = {}; const actionMap: { [name: string]: Function | undefined } = {};
@ -25,4 +27,16 @@ export class ActionController {
} }
async run(args: Args, task: Task) {} async run(args: Args, task: Task) {}
ensureSameVillage(args: Args, task: Task) {
let villageId = args.villageId;
if (villageId === undefined) {
throw new ActionError(task.id, 'Undefined village id');
}
const activeVillageId = grabActiveVillageId();
if (villageId !== activeVillageId) {
throw new TryLaterError(task.id, aroundMinutes(1), 'Not same village');
}
}
} }

View File

@ -3,20 +3,23 @@ import { Args } from '../Command';
import { ActionError, GrabError, TryLaterError } from '../Errors'; import { ActionError, GrabError, TryLaterError } from '../Errors';
import { Task } from '../Queue/TaskQueue'; import { Task } from '../Queue/TaskQueue';
import { clickBuildButton } from '../Page/BuildingPage'; import { clickBuildButton } from '../Page/BuildingPage';
import { aroundMinutes } from '../utils';
@registerAction @registerAction
export class BuildBuildingAction extends ActionController { export class BuildBuildingAction extends ActionController {
async run(args: Args, task: Task): Promise<any> { async run(args: Args, task: Task): Promise<any> {
this.ensureSameVillage(args, task);
const buildTypeId = args.buildTypeId; const buildTypeId = args.buildTypeId;
if (!buildTypeId) { if (buildTypeId === undefined) {
throw new ActionError(task.id, 'Unknown build type id'); throw new ActionError(task.id, 'Undefined build type id');
} }
try { try {
clickBuildButton(buildTypeId); clickBuildButton(buildTypeId);
} catch (e) { } catch (e) {
if (e instanceof GrabError) { if (e instanceof GrabError) {
throw new TryLaterError(task.id, 15 * 60, 'No build button, try later'); throw new TryLaterError(task.id, aroundMinutes(5), 'No upgrade button, try later');
} }
throw e; throw e;
} }

View File

@ -1,8 +1,8 @@
import { ActionController, registerAction } from './ActionController'; import { ActionController, registerAction } from './ActionController';
import { Args } from '../Command'; import { Args } from '../Command';
import { Task } from '../Queue/TaskQueue'; import { Task } from '../Queue/TaskQueue';
import { PostponeAllBuildingsError, GrabError } from '../Errors'; import { GrabError, TryLaterError } from '../Errors';
import { grabActiveVillageId, grabBuildingQueueInfo } from '../Page/VillageBlock'; import { grabBuildingQueueInfo } from '../Page/VillageBlock';
import { BuildingQueueInfo } from '../Game'; import { BuildingQueueInfo } from '../Game';
@registerAction @registerAction
@ -10,12 +10,7 @@ export class CheckBuildingRemainingTimeAction extends ActionController {
async run(args: Args, task: Task): Promise<any> { async run(args: Args, task: Task): Promise<any> {
const info = this.grabBuildingQueueInfoOrDefault(); const info = this.grabBuildingQueueInfoOrDefault();
if (info.seconds > 0) { if (info.seconds > 0) {
throw new PostponeAllBuildingsError( throw new TryLaterError(task.id, info.seconds + 1, 'Building queue is full');
task.id,
grabActiveVillageId(),
info.seconds + 1,
'Building queue is full'
);
} }
} }

View File

@ -1,22 +1,20 @@
import { ActionController, registerAction } from './ActionController'; import { ActionController, registerAction } from './ActionController';
import { Args } from '../Command'; import { Args } from '../Command';
import { ActionError, GrabError, PostponeAllBuildingsError } from '../Errors'; import { GrabError, TryLaterError } from '../Errors';
import { Task } from '../Queue/TaskQueue'; import { Task } from '../Queue/TaskQueue';
import { clickUpgradeButton } from '../Page/BuildingPage'; import { clickUpgradeButton } from '../Page/BuildingPage';
import { aroundMinutes } from '../utils';
@registerAction @registerAction
export class UpgradeBuildingAction extends ActionController { export class UpgradeBuildingAction extends ActionController {
async run(args: Args, task: Task): Promise<any> { async run(args: Args, task: Task): Promise<any> {
let villageId = args.villageId; this.ensureSameVillage(args, task);
if (villageId === undefined) {
throw new ActionError(task.id, 'No village id');
}
try { try {
clickUpgradeButton(); clickUpgradeButton();
} catch (e) { } catch (e) {
if (e instanceof GrabError) { if (e instanceof GrabError) {
throw new PostponeAllBuildingsError(task.id, villageId, 15 * 60, 'No upgrade button, try later'); throw new TryLaterError(task.id, aroundMinutes(5), 'No upgrade button, try later');
} }
throw e; throw e;
} }

View File

@ -36,17 +36,3 @@ export class TryLaterError extends Error {
Object.setPrototypeOf(this, TryLaterError.prototype); Object.setPrototypeOf(this, TryLaterError.prototype);
} }
} }
export class PostponeAllBuildingsError extends Error {
readonly seconds: number;
readonly villageId: number;
readonly taskId: TaskId;
constructor(taskId: TaskId, villageId: number, seconds: number, msg: string = '') {
super(msg);
this.villageId = villageId;
this.taskId = taskId;
this.seconds = seconds;
Object.setPrototypeOf(this, PostponeAllBuildingsError.prototype);
}
}

View File

@ -1,5 +1,5 @@
import { markPage, sleepMicro, timestamp, waitForLoad } from './utils'; import { markPage, sleepMicro, timestamp, waitForLoad } from './utils';
import { AbortTaskError, ActionError, PostponeAllBuildingsError, TryLaterError } from './Errors'; import { AbortTaskError, ActionError, TryLaterError } from './Errors';
import { Task } from './Queue/TaskQueue'; import { Task } from './Queue/TaskQueue';
import { Command } from './Command'; import { Command } from './Command';
import { TaskQueueRenderer } from './TaskQueueRenderer'; import { TaskQueueRenderer } from './TaskQueueRenderer';
@ -108,12 +108,6 @@ export class Executor {
return; return;
} }
if (err instanceof PostponeAllBuildingsError) {
this.logger.warn('BUILDING QUEUE FULL, TRY ALL AFTER', err.seconds);
this.scheduler.postponeBuildingsInVillage(err.villageId, err.seconds);
return;
}
if (err instanceof ActionError) { if (err instanceof ActionError) {
this.logger.warn('ACTION ABORTED', err.message); this.logger.warn('ACTION ABORTED', err.message);
return; return;

View File

@ -73,28 +73,32 @@ export class Scheduler {
} }
} }
completeTask(id: TaskId) { completeTask(taskId: TaskId) {
this.taskQueue.remove(id); this.taskQueue.remove(taskId);
this.actionQueue.clear(); this.actionQueue.clear();
} }
removeTask(id: TaskId) { removeTask(taskId: TaskId) {
this.taskQueue.remove(id); this.taskQueue.remove(taskId);
this.actionQueue.clear(); this.actionQueue.clear();
} }
postponeTask(id: TaskId, deltaTs: number) { postponeTask(taskId: TaskId, seconds: number) {
this.taskQueue.modify( const task = this.taskQueue.seeItems().find(t => t.id === taskId);
t => t.id === id, if (!task) {
t => withTime(t, timestamp() + deltaTs) return;
); }
} if (isBuildingTask(task.name) && task.args.villageId) {
this.taskQueue.modify(
postponeBuildingsInVillage(villageId: number, seconds: number) { t => sameVillage(task.args.villageId, t.args),
this.taskQueue.modify( t => withTime(t, timestamp() + seconds)
t => isBuildingTask(t.name) && sameVillage(villageId, t.args), );
t => withTime(t, timestamp() + seconds) } else {
); this.taskQueue.modify(
t => t.id === taskId,
t => withTime(t, timestamp() + seconds)
);
}
} }
updateResources(taskId: TaskId, resources: Resources): void { updateResources(taskId: TaskId, resources: Resources): void {