Simplify work with errors
This commit is contained in:
		| @@ -31,12 +31,12 @@ export class ActionController { | ||||
|     ensureSameVillage(args: Args, task: Task) { | ||||
|         let villageId = args.villageId; | ||||
|         if (villageId === undefined) { | ||||
|             throw new ActionError(task.id, 'Undefined village id'); | ||||
|             throw new ActionError('Undefined village id'); | ||||
|         } | ||||
|  | ||||
|         const activeVillageId = grabActiveVillageId(); | ||||
|         if (villageId !== activeVillageId) { | ||||
|             throw new TryLaterError(task.id, aroundMinutes(1), 'Not same village'); | ||||
|             throw new TryLaterError(aroundMinutes(1), 'Not same village'); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -12,14 +12,14 @@ export class BuildBuildingAction extends ActionController { | ||||
|  | ||||
|         const buildTypeId = args.buildTypeId; | ||||
|         if (buildTypeId === undefined) { | ||||
|             throw new ActionError(task.id, 'Undefined build type id'); | ||||
|             throw new ActionError('Undefined build type id'); | ||||
|         } | ||||
|  | ||||
|         try { | ||||
|             clickBuildButton(buildTypeId); | ||||
|         } catch (e) { | ||||
|             if (e instanceof GrabError) { | ||||
|                 throw new TryLaterError(task.id, aroundMinutes(5), 'No upgrade button, try later'); | ||||
|                 throw new TryLaterError(aroundMinutes(5), 'No upgrade button, try later'); | ||||
|             } | ||||
|             throw e; | ||||
|         } | ||||
|   | ||||
| @@ -10,7 +10,7 @@ export class CheckBuildingRemainingTimeAction extends ActionController { | ||||
|     async run(args: Args, task: Task): Promise<any> { | ||||
|         const info = this.grabBuildingQueueInfoOrDefault(); | ||||
|         if (info.seconds > 0) { | ||||
|             throw new TryLaterError(task.id, info.seconds + 1, 'Building queue is full'); | ||||
|             throw new TryLaterError(info.seconds + 1, 'Building queue is full'); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -37,7 +37,7 @@ export class SendOnAdventureAction extends ActionController { | ||||
|             this.checkConfig(easiest, Number(hero.health)); | ||||
|         } | ||||
|  | ||||
|         throw new AbortTaskError(task.id, 'No suitable adventure'); | ||||
|         throw new AbortTaskError('No suitable adventure'); | ||||
|     } | ||||
|  | ||||
|     private checkConfig(adventure: Adventure, health: number) { | ||||
|   | ||||
| @@ -7,50 +7,50 @@ import { getNumber, toNumber } from '../utils'; | ||||
| @registerAction | ||||
| export class TrainTrooperAction extends ActionController { | ||||
|     async run(args: Args, task: Task): Promise<any> { | ||||
|         const troopId = this.getTroopId(args, task); | ||||
|         const trainCount = this.getTrainCount(args, task); | ||||
|         const troopId = this.getTroopId(args); | ||||
|         const trainCount = this.getTrainCount(args); | ||||
|  | ||||
|         const block = jQuery(`#nonFavouriteTroops .innerTroopWrapper.troop${troopId}`); | ||||
|         if (block.length !== 1) { | ||||
|             throw new ActionError(task.id, `Troop block not found`); | ||||
|             throw new ActionError(`Troop block not found`); | ||||
|         } | ||||
|  | ||||
|         const countLink = block.find('.cta a'); | ||||
|         if (countLink.length !== 1) { | ||||
|             throw new ActionError(task.id, `Link with max count not found`); | ||||
|             throw new ActionError(`Link with max count not found`); | ||||
|         } | ||||
|  | ||||
|         const maxCount = getNumber(countLink.text()); | ||||
|         if (maxCount < trainCount) { | ||||
|             throw new TryLaterError(task.id, 20 * 60, `Max count ${maxCount} less then need ${trainCount}`); | ||||
|             throw new TryLaterError(20 * 60, `Max count ${maxCount} less then need ${trainCount}`); | ||||
|         } | ||||
|  | ||||
|         const input = block.find(`input[name="t${troopId}"]`); | ||||
|         if (input.length !== 1) { | ||||
|             throw new ActionError(task.id, `Input element not found`); | ||||
|             throw new ActionError(`Input element not found`); | ||||
|         } | ||||
|  | ||||
|         const trainButton = jQuery('.startTraining.green').first(); | ||||
|         if (trainButton.length !== 1) { | ||||
|             throw new ActionError(task.id, 'Train button not found'); | ||||
|             throw new ActionError('Train button not found'); | ||||
|         } | ||||
|  | ||||
|         input.val(trainCount); | ||||
|         trainButton.trigger('click'); | ||||
|     } | ||||
|  | ||||
|     private getTroopId(args: Args, task: Task): number { | ||||
|     private getTroopId(args: Args): number { | ||||
|         const troopId = toNumber(args.troopId); | ||||
|         if (troopId === undefined) { | ||||
|             throw new ActionError(task.id, `Troop id must be a number, given "${args.troopId}"`); | ||||
|             throw new ActionError(`Troop id must be a number, given "${args.troopId}"`); | ||||
|         } | ||||
|         return troopId; | ||||
|     } | ||||
|  | ||||
|     private getTrainCount(args: Args, task: Task): number { | ||||
|     private getTrainCount(args: Args): number { | ||||
|         const trainCount = toNumber(args.trainCount); | ||||
|         if (trainCount === undefined) { | ||||
|             throw new ActionError(task.id, `Train count must be a number, given "${args.trainCount}"`); | ||||
|             throw new ActionError(`Train count must be a number, given "${args.trainCount}"`); | ||||
|         } | ||||
|         return trainCount; | ||||
|     } | ||||
|   | ||||
| @@ -14,7 +14,7 @@ export class UpgradeBuildingAction extends ActionController { | ||||
|             clickUpgradeButton(); | ||||
|         } catch (e) { | ||||
|             if (e instanceof GrabError) { | ||||
|                 throw new TryLaterError(task.id, aroundMinutes(5), 'No upgrade button, try later'); | ||||
|                 throw new TryLaterError(aroundMinutes(5), 'No upgrade button, try later'); | ||||
|             } | ||||
|             throw e; | ||||
|         } | ||||
|   | ||||
| @@ -1,8 +1,7 @@ | ||||
| import { ActionController, registerAction } from './ActionController'; | ||||
| import { Args } from '../Command'; | ||||
| import { ActionError, GrabError, TryLaterError } from '../Errors'; | ||||
| import { ActionError, TryLaterError } from '../Errors'; | ||||
| import { Task } from '../Queue/TaskQueue'; | ||||
| import { clickUpgradeButton } from '../Page/BuildingPage'; | ||||
| import { grabResourceDeposits } from '../Page/SlotBlock'; | ||||
| import { UpgradeBuildingTask } from '../Task/UpgradeBuildingTask'; | ||||
| import { ResourceDeposit } from '../Game'; | ||||
| @@ -13,7 +12,7 @@ export class UpgradeResourceToLevel extends ActionController { | ||||
|     async run(args: Args, task: Task): Promise<any> { | ||||
|         const deposits = grabResourceDeposits(); | ||||
|         if (deposits.length === 0) { | ||||
|             throw new ActionError(task.id, 'No deposits'); | ||||
|             throw new ActionError('No deposits'); | ||||
|         } | ||||
|  | ||||
|         const villageId = args.villageId; | ||||
| @@ -39,13 +38,13 @@ export class UpgradeResourceToLevel extends ActionController { | ||||
|         const notUpgraded = deposits.sort((x, y) => x.level - y.level).filter(isDepositTaskNotInQueue); | ||||
|  | ||||
|         if (notUpgraded.length === 0) { | ||||
|             throw new TryLaterError(task.id, aroundMinutes(10), 'No available deposits'); | ||||
|             throw new TryLaterError(aroundMinutes(10), 'No available deposits'); | ||||
|         } | ||||
|  | ||||
|         for (let dep of notUpgraded) { | ||||
|             this.scheduler.scheduleTask(UpgradeBuildingTask.name, { villageId, buildId: dep.buildId }); | ||||
|         } | ||||
|  | ||||
|         throw new TryLaterError(task.id, aroundMinutes(10), 'Sleep for next round'); | ||||
|         throw new TryLaterError(aroundMinutes(10), 'Sleep for next round'); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,5 +1,3 @@ | ||||
| import { TaskId } from './Queue/TaskQueue'; | ||||
|  | ||||
| export class GrabError extends Error { | ||||
|     constructor(msg: string = '') { | ||||
|         super(msg); | ||||
| @@ -8,30 +6,24 @@ export class GrabError extends Error { | ||||
| } | ||||
|  | ||||
| export class ActionError extends Error { | ||||
|     readonly taskId: TaskId; | ||||
|     constructor(taskId: TaskId, msg: string = '') { | ||||
|     constructor(msg: string = '') { | ||||
|         super(msg); | ||||
|         this.taskId = taskId; | ||||
|         Object.setPrototypeOf(this, ActionError.prototype); | ||||
|     } | ||||
| } | ||||
|  | ||||
| export class AbortTaskError extends Error { | ||||
|     readonly taskId: TaskId; | ||||
|     constructor(taskId: TaskId, msg: string = '') { | ||||
|     constructor(msg: string = '') { | ||||
|         super(msg); | ||||
|         this.taskId = taskId; | ||||
|         Object.setPrototypeOf(this, AbortTaskError.prototype); | ||||
|     } | ||||
| } | ||||
|  | ||||
| export class TryLaterError extends Error { | ||||
|     readonly seconds: number; | ||||
|     readonly taskId: TaskId; | ||||
|  | ||||
|     constructor(taskId: TaskId, seconds: number, msg: string = '') { | ||||
|     constructor(seconds: number, msg: string = '') { | ||||
|         super(msg); | ||||
|         this.taskId = taskId; | ||||
|         this.seconds = seconds; | ||||
|         Object.setPrototypeOf(this, TryLaterError.prototype); | ||||
|     } | ||||
|   | ||||
| @@ -43,10 +43,10 @@ export class Executor { | ||||
|         await sleepMicro(); | ||||
|  | ||||
|         const currentTs = timestamp(); | ||||
|         const taskCommand = this.scheduler.nextTask(currentTs); | ||||
|         const task = this.scheduler.nextTask(currentTs); | ||||
|  | ||||
|         // текущего таска нет, очищаем очередь действий по таску | ||||
|         if (!taskCommand) { | ||||
|         if (!task) { | ||||
|             this.logger.log('NO ACTIVE TASK'); | ||||
|             this.scheduler.clearActions(); | ||||
|             return; | ||||
| @@ -54,26 +54,29 @@ export class Executor { | ||||
|  | ||||
|         const actionCommand = this.scheduler.nextAction(); | ||||
|  | ||||
|         this.logger.log('CURRENT JOB', 'TASK', taskCommand, 'ACTION', actionCommand); | ||||
|         this.logger.log('CURRENT JOB', 'TASK', task, 'ACTION', actionCommand); | ||||
|  | ||||
|         this.runGrabbers(); | ||||
|  | ||||
|         try { | ||||
|             if (actionCommand) { | ||||
|                 return await this.processActionCommand(actionCommand, taskCommand); | ||||
|                 return await this.processActionCommand(actionCommand, task); | ||||
|             } | ||||
|  | ||||
|             if (taskCommand) { | ||||
|                 return await this.processTaskCommand(taskCommand); | ||||
|             if (task) { | ||||
|                 return await this.processTaskCommand(task); | ||||
|             } | ||||
|         } catch (e) { | ||||
|             this.handleError(e); | ||||
|             this.handleError(e, task); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private async processActionCommand(cmd: Command, task: Task) { | ||||
|         const actionController = createAction(cmd.name, this.scheduler); | ||||
|         this.logger.log('PROCESS ACTION', cmd.name, actionController); | ||||
|         if (cmd.args.taskId !== task.id) { | ||||
|             throw new ActionError(`Action task id ${cmd.args.taskId} not equal current task id ${task.id}`); | ||||
|         } | ||||
|         if (actionController) { | ||||
|             await actionController.run(cmd.args, task); | ||||
|         } else { | ||||
| @@ -92,19 +95,19 @@ export class Executor { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private handleError(err: Error) { | ||||
|     private handleError(err: Error, task: Task) { | ||||
|         this.scheduler.clearActions(); | ||||
|  | ||||
|         if (err instanceof AbortTaskError) { | ||||
|             this.logger.warn('ABORT TASK', err.taskId); | ||||
|             this.scheduler.completeTask(err.taskId); | ||||
|             this.logger.warn('ABORT TASK', task.id); | ||||
|             this.scheduler.completeTask(task.id); | ||||
|             this.scheduler.clearActions(); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         if (err instanceof TryLaterError) { | ||||
|             this.logger.warn('TRY', err.taskId, 'AFTER', err.seconds); | ||||
|             this.scheduler.postponeTask(err.taskId, err.seconds); | ||||
|             this.logger.warn('TRY', task.id, 'AFTER', err.seconds); | ||||
|             this.scheduler.postponeTask(task.id, err.seconds); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user