Refactoring and task queue tests

This commit is contained in:
Anton Vakhrushev 2020-04-29 20:43:56 +03:00
parent cd7d9f0800
commit a675a4f286
34 changed files with 149 additions and 102 deletions

@ -1,9 +1,9 @@
import { Task } from '../Queue/TaskQueue';
import { Scheduler } from '../Scheduler';
import { ActionError, TryLaterError } from '../Errors';
import { grabActiveVillageId } from '../Page/VillageBlock';
import { aroundMinutes } from '../utils';
import { Args } from '../Queue/Args';
import { Task } from '../Queue/TaskProvider';
const actionMap: { [name: string]: Function | undefined } = {};

@ -1,5 +1,4 @@
import { ActionController, registerAction } from './ActionController';
import { Task } from '../Queue/TaskQueue';
import { grabVillageResources, grabVillageResourceStorage } from '../Page/ResourcesBlock';
import { changeHeroResource, grabCurrentHeroResource } from '../Page/HeroPage';
import { grabActiveVillageId } from '../Page/VillageBlock';
@ -7,6 +6,7 @@ import { HeroState } from '../State/HeroState';
import { calcHeroResource } from '../Core/HeroBalance';
import { HeroAllResources } from '../Core/Hero';
import { Args } from '../Queue/Args';
import { Task } from '../Queue/TaskProvider';
@registerAction
export class BalanceHeroResourcesAction extends ActionController {

@ -1,9 +1,9 @@
import { ActionController, registerAction } from './ActionController';
import { ActionError, GrabError, TryLaterError } from '../Errors';
import { Task } from '../Queue/TaskQueue';
import { clickBuildButton } from '../Page/BuildingPage';
import { aroundMinutes } from '../utils';
import { Args } from '../Queue/Args';
import { Task } from '../Queue/TaskProvider';
@registerAction
export class BuildBuildingAction extends ActionController {

@ -1,9 +1,9 @@
import { ActionController, registerAction } from './ActionController';
import { Task } from '../Queue/TaskQueue';
import { GrabError, TryLaterError } from '../Errors';
import { grabBuildingQueueInfo } from '../Page/VillageBlock';
import { BuildingQueueInfo } from '../Game';
import { Args } from '../Queue/Args';
import { Task } from '../Queue/TaskProvider';
@registerAction
export class CheckBuildingRemainingTimeAction extends ActionController {

@ -1,7 +1,7 @@
import { ActionController, registerAction } from './ActionController';
import { Task } from '../Queue/TaskQueue';
import { AbortTaskError } from '../Errors';
import { Args } from '../Queue/Args';
import { Task } from '../Queue/TaskProvider';
@registerAction
export class ClickButtonAction extends ActionController {

@ -1,6 +1,6 @@
import { ActionController, registerAction } from './ActionController';
import { Task } from '../Queue/TaskQueue';
import { Args } from '../Queue/Args';
import { Task } from '../Queue/TaskProvider';
@registerAction
export class CompleteTaskAction extends ActionController {

@ -1,10 +1,10 @@
import { ActionController, registerAction } from './ActionController';
import { Task } from '../Queue/TaskQueue';
import { grabVillageList } from '../Page/VillageBlock';
import { grabHeroVillage } from '../Page/HeroPage';
import { path } from '../utils';
import { HeroState } from '../State/HeroState';
import { Args } from '../Queue/Args';
import { Task } from '../Queue/TaskProvider';
@registerAction
export class GoToHeroVillageAction extends ActionController {

@ -1,7 +1,7 @@
import { ActionController, registerAction } from './ActionController';
import { Task } from '../Queue/TaskQueue';
import { AbortTaskError } from '../Errors';
import { Args } from '../Queue/Args';
import { Task } from '../Queue/TaskProvider';
@registerAction
export class GoToPageAction extends ActionController {

@ -1,8 +1,8 @@
import { ActionController, registerAction } from './ActionController';
import { Task } from '../Queue/TaskQueue';
import { trimPrefix } from '../utils';
import { AbortTaskError } from '../Errors';
import { Args } from '../Queue/Args';
import { Task } from '../Queue/TaskProvider';
const CONFIG = [
{ level: 0, health: 60 },

@ -1,6 +1,5 @@
import { ActionController, registerAction } from './ActionController';
import { AbortTaskError, ActionError, TryLaterError } from '../Errors';
import { Task } from '../Queue/TaskQueue';
import { Resources } from '../Core/Resources';
import { Coordinates, Village } from '../Core/Village';
import { clickSendButton, fillSendResourcesForm, grabMerchantsInfo } from '../Page/BuildingPage';
@ -10,6 +9,7 @@ import { SendResourcesTask } from '../Task/SendResourcesTask';
import { aroundMinutes, timestamp } from '../utils';
import { VillageState } from '../State/VillageState';
import { Args } from '../Queue/Args';
import { Task } from '../Queue/TaskProvider';
function err(msg): never {
throw new ActionError(msg);

@ -1,8 +1,8 @@
import { ActionController, registerAction } from './ActionController';
import { ActionError, TryLaterError } from '../Errors';
import { Task } from '../Queue/TaskQueue';
import { getNumber, toNumber } from '../utils';
import { Args } from '../Queue/Args';
import { Task } from '../Queue/TaskProvider';
@registerAction
export class TrainTrooperAction extends ActionController {

@ -1,7 +1,7 @@
import { ActionController, registerAction } from './ActionController';
import { Task } from '../Queue/TaskQueue';
import { grabContractResources } from '../Page/BuildingPage';
import { Args } from '../Queue/Args';
import { Task } from '../Queue/TaskProvider';
@registerAction
export class UpdateBuildingTaskResourcesAction extends ActionController {

@ -1,9 +1,9 @@
import { ActionController, registerAction } from './ActionController';
import { GrabError, TryLaterError } from '../Errors';
import { Task } from '../Queue/TaskQueue';
import { clickUpgradeButton } from '../Page/BuildingPage';
import { aroundMinutes } from '../utils';
import { Args } from '../Queue/Args';
import { Task } from '../Queue/TaskProvider';
@registerAction
export class UpgradeBuildingAction extends ActionController {

@ -1,11 +1,11 @@
import { ActionController, registerAction } from './ActionController';
import { AbortTaskError, ActionError, TryLaterError } from '../Errors';
import { Task } from '../Queue/TaskQueue';
import { grabResourceDeposits } from '../Page/SlotBlock';
import { UpgradeBuildingTask } from '../Task/UpgradeBuildingTask';
import { ResourceDeposit } from '../Game';
import { aroundMinutes, getNumber } from '../utils';
import { Args } from '../Queue/Args';
import { Task } from '../Queue/TaskProvider';
@registerAction
export class UpgradeResourceToLevel extends ActionController {

@ -1,9 +1,10 @@
import { Scheduler } from './Scheduler';
import { DataStorageTaskProvider, TaskQueue } from './Queue/TaskQueue';
import { TaskQueue } from './Queue/TaskQueue';
import { ConsoleLogger } from './Logger';
import { ActionQueue } from './Queue/ActionQueue';
import { Executor } from './Executor';
import { ControlPanel } from './ControlPanel';
import { DataStorageTaskProvider } from './Queue/DataStorageTaskProvider';
export class Container {
private readonly version: string;

@ -1,6 +1,5 @@
import { markPage, sleepMicro, timestamp, waitForLoad } from './utils';
import { AbortTaskError, ActionError, TryLaterError } from './Errors';
import { Task } from './Queue/TaskQueue';
import { TaskQueueRenderer } from './TaskQueueRenderer';
import { createActionHandler } from './Action/ActionController';
import { createTaskHandler } from './Task/TaskController';
@ -10,6 +9,7 @@ import { Scheduler } from './Scheduler';
import { Statistics } from './Statistics';
import { ExecutionState } from './State/ExecutionState';
import { Action } from './Queue/ActionQueue';
import { Task } from './Queue/TaskProvider';
export interface ExecutionSettings {
pauseTs: number;

@ -1,6 +1,6 @@
import { TaskId } from './TaskQueue';
import { ResourcesInterface } from '../Core/Resources';
import { CoordinatesInterface } from '../Core/Village';
import { TaskId } from './TaskProvider';
export interface Args {
taskId?: TaskId;

@ -0,0 +1,17 @@
import { TaskList, TaskProvider } from './TaskProvider';
export class ArrayTaskProvider implements TaskProvider {
private tasks: TaskList;
constructor(tasks: TaskList) {
this.tasks = tasks;
}
getTasks(): TaskList {
return this.tasks;
}
setTasks(tasks: TaskList): void {
this.tasks = tasks;
}
}

@ -0,0 +1,36 @@
import { DataStorage } from '../DataStorage';
import { uniqId } from '../utils';
import { Task, TaskList, TaskProvider } from './TaskProvider';
const NAMESPACE = 'tasks:v1';
const QUEUE_NAME = 'queue';
export class DataStorageTaskProvider implements TaskProvider {
private storage: DataStorage;
constructor(storage: DataStorage) {
this.storage = storage;
}
static create() {
return new DataStorageTaskProvider(new DataStorage(NAMESPACE));
}
getTasks(): TaskList {
const serialized = this.storage.get(QUEUE_NAME);
if (!Array.isArray(serialized)) {
return [];
}
const storedItems = serialized as Array<{ [key: string]: any }>;
return storedItems.map(i => {
const task = new Task(uniqId(), 0, '', {});
return Object.assign(task, i);
});
}
setTasks(tasks: TaskList): void {
this.storage.set(QUEUE_NAME, tasks);
}
}

41
src/Queue/TaskProvider.ts Normal file

@ -0,0 +1,41 @@
import { Args } from './Args';
import { uniqId } from '../utils';
export type TaskId = string;
let idSequence = 1;
let lastTimestamp: number | null = null;
export function uniqTaskId(): TaskId {
const ts = Math.floor(Date.now() / 1000);
if (ts === lastTimestamp) {
++idSequence;
} else {
idSequence = 1;
}
lastTimestamp = ts;
return 'tid.' + ts + '.' + String(idSequence).padStart(4, '0') + '.' + uniqId('');
}
export class Task {
readonly id: TaskId;
readonly ts: number;
readonly name: string;
readonly args: Args;
constructor(id: TaskId, ts: number, name: string, args: Args) {
this.id = id;
this.ts = ts;
this.name = name;
this.args = args;
}
}
export type TaskList = Array<Task>;
export type ImmutableTaskList = ReadonlyArray<Task>;
export interface TaskProvider {
getTasks(): TaskList;
setTasks(tasks: TaskList): void;
}

@ -1,78 +1,6 @@
import { uniqId } from '../utils';
import { Logger } from '../Logger';
import { DataStorage } from '../DataStorage';
import { Args } from './Args';
const NAMESPACE = 'tasks:v1';
const QUEUE_NAME = 'queue';
export type TaskId = string;
let idSequence = 1;
let lastTimestamp: number | null = null;
function uniqTaskId(): TaskId {
const ts = Math.floor(Date.now() / 1000);
if (ts === lastTimestamp) {
++idSequence;
} else {
idSequence = 1;
}
lastTimestamp = ts;
return 'tid.' + ts + '.' + String(idSequence).padStart(4, '0') + '.' + uniqId('');
}
export class Task {
readonly id: TaskId;
readonly ts: number;
readonly name: string;
readonly args: Args;
constructor(id: TaskId, ts: number, name: string, args: Args) {
this.id = id;
this.ts = ts;
this.name = name;
this.args = args;
}
}
type TaskList = Array<Task>;
export type ImmutableTaskList = ReadonlyArray<Task>;
export interface TaskProvider {
getTasks(): TaskList;
setTasks(tasks: TaskList): void;
}
export class DataStorageTaskProvider implements TaskProvider {
private storage: DataStorage;
constructor(storage: DataStorage) {
this.storage = storage;
}
static create() {
return new DataStorageTaskProvider(new DataStorage(NAMESPACE));
}
getTasks(): TaskList {
const serialized = this.storage.get(QUEUE_NAME);
if (!Array.isArray(serialized)) {
return [];
}
const storedItems = serialized as Array<{ [key: string]: any }>;
return storedItems.map(i => {
const task = new Task(uniqId(), 0, '', {});
return Object.assign(task, i);
});
}
setTasks(tasks: TaskList): void {
this.storage.set(QUEUE_NAME, tasks);
}
}
import { ImmutableTaskList, Task, TaskId, TaskList, TaskProvider, uniqTaskId } from './TaskProvider';
export class TaskQueue {
private provider: TaskProvider;

@ -1,6 +1,6 @@
import { timestamp } from './utils';
import { UpgradeBuildingTask } from './Task/UpgradeBuildingTask';
import { ImmutableTaskList, Task, TaskId, TaskQueue } from './Queue/TaskQueue';
import { TaskQueue } from './Queue/TaskQueue';
import { SendOnAdventureTask } from './Task/SendOnAdventureTask';
import { BalanceHeroResourcesTask } from './Task/BalanceHeroResourcesTask';
import { Logger } from './Logger';
@ -12,6 +12,7 @@ import { TrainTroopTask } from './Task/TrainTroopTask';
import { Resources, ResourcesInterface } from './Core/Resources';
import { SendResourcesTask } from './Task/SendResourcesTask';
import { Args } from './Queue/Args';
import { ImmutableTaskList, Task, TaskId } from './Queue/TaskProvider';
export class Scheduler {
private taskQueue: TaskQueue;

@ -1,4 +1,3 @@
import { Task } from '../Queue/TaskQueue';
import { TaskController, registerTask } from './TaskController';
import { GoToPageAction } from '../Action/GoToPageAction';
import { CompleteTaskAction } from '../Action/CompleteTaskAction';
@ -7,6 +6,7 @@ import { path } from '../utils';
import { GoToHeroVillageAction } from '../Action/GoToHeroVillageAction';
import { Action } from '../Queue/ActionQueue';
import { Args } from '../Queue/Args';
import { Task } from '../Queue/TaskProvider';
@registerTask
export class BalanceHeroResourcesTask extends TaskController {

@ -3,10 +3,10 @@ import { CheckBuildingRemainingTimeAction } from '../Action/CheckBuildingRemaini
import { CompleteTaskAction } from '../Action/CompleteTaskAction';
import { GoToPageAction } from '../Action/GoToPageAction';
import { path } from '../utils';
import { Task } from '../Queue/TaskQueue';
import { TaskController, registerTask } from './TaskController';
import { Action } from '../Queue/ActionQueue';
import { Args } from '../Queue/Args';
import { Task } from '../Queue/TaskProvider';
@registerTask
export class BuildBuildingTask extends TaskController {

@ -1,6 +1,6 @@
import { TaskController, registerTask, ActionDefinition } from './TaskController';
import { scanAllVillagesBundle } from './ActionBundles';
import { Task } from '../Queue/TaskQueue';
import { Task } from '../Queue/TaskProvider';
@registerTask
export class GrabVillageState extends TaskController {

@ -1,4 +1,3 @@
import { Task } from '../Queue/TaskQueue';
import { TaskController, registerTask, ActionDefinition } from './TaskController';
import { GoToPageAction } from '../Action/GoToPageAction';
import { CompleteTaskAction } from '../Action/CompleteTaskAction';
@ -6,6 +5,7 @@ import { path } from '../utils';
import { UpgradeResourceToLevel } from '../Action/UpgradeResourceToLevel';
import { Action } from '../Queue/ActionQueue';
import { Args } from '../Queue/Args';
import { Task } from '../Queue/TaskProvider';
@registerTask
export class ResourcesToLevel extends TaskController {

@ -1,4 +1,3 @@
import { Task } from '../Queue/TaskQueue';
import { TaskController, registerTask } from './TaskController';
import { GoToPageAction } from '../Action/GoToPageAction';
import { CompleteTaskAction } from '../Action/CompleteTaskAction';
@ -7,6 +6,7 @@ import { ClickButtonAction } from '../Action/ClickButtonAction';
import { path } from '../utils';
import { Action } from '../Queue/ActionQueue';
import { Args } from '../Queue/Args';
import { Task } from '../Queue/TaskProvider';
@registerTask
export class SendOnAdventureTask extends TaskController {

@ -1,4 +1,3 @@
import { Task } from '../Queue/TaskQueue';
import { TaskController, registerTask, ActionDefinition } from './TaskController';
import { GoToPageAction } from '../Action/GoToPageAction';
import { CompleteTaskAction } from '../Action/CompleteTaskAction';
@ -7,6 +6,7 @@ import { SendResourcesAction } from '../Action/SendResourcesAction';
import { ClickButtonAction } from '../Action/ClickButtonAction';
import { scanAllVillagesBundle } from './ActionBundles';
import { Args } from '../Queue/Args';
import { Task } from '../Queue/TaskProvider';
@registerTask
export class SendResourcesTask extends TaskController {

@ -1,8 +1,8 @@
import { Task } from '../Queue/TaskQueue';
import { Scheduler } from '../Scheduler';
import { CompleteTaskAction } from '../Action/CompleteTaskAction';
import { Action } from '../Queue/ActionQueue';
import { Args } from '../Queue/Args';
import { Task } from '../Queue/TaskProvider';
const taskMap: { [name: string]: Function | undefined } = {};

@ -1,4 +1,3 @@
import { Task } from '../Queue/TaskQueue';
import { TaskController, registerTask } from './TaskController';
import { GoToPageAction } from '../Action/GoToPageAction';
import { CompleteTaskAction } from '../Action/CompleteTaskAction';
@ -6,6 +5,7 @@ import { TrainTrooperAction } from '../Action/TrainTrooperAction';
import { path } from '../utils';
import { Action } from '../Queue/ActionQueue';
import { Args } from '../Queue/Args';
import { Task } from '../Queue/TaskProvider';
@registerTask
export class TrainTroopTask extends TaskController {

@ -1,4 +1,3 @@
import { Task } from '../Queue/TaskQueue';
import { TaskController, registerTask } from './TaskController';
import { GoToPageAction } from '../Action/GoToPageAction';
import { path } from '../utils';
@ -7,6 +6,7 @@ import { UpdateBuildingTaskResourcesAction } from '../Action/UpdateBuildingTaskR
import { CompleteTaskAction } from '../Action/CompleteTaskAction';
import { Action } from '../Queue/ActionQueue';
import { Args } from '../Queue/Args';
import { Task } from '../Queue/TaskProvider';
@registerTask
export class UpdateResourceContracts extends TaskController {

@ -1,5 +1,4 @@
import { UpgradeBuildingAction } from '../Action/UpgradeBuildingAction';
import { Task } from '../Queue/TaskQueue';
import { TaskController, registerTask } from './TaskController';
import { GoToPageAction } from '../Action/GoToPageAction';
import { CheckBuildingRemainingTimeAction } from '../Action/CheckBuildingRemainingTimeAction';
@ -7,6 +6,7 @@ import { CompleteTaskAction } from '../Action/CompleteTaskAction';
import { path } from '../utils';
import { Action } from '../Queue/ActionQueue';
import { Args } from '../Queue/Args';
import { Task } from '../Queue/TaskProvider';
@registerTask
export class UpgradeBuildingTask extends TaskController {

@ -1,6 +1,6 @@
import { ImmutableTaskList } from './Queue/TaskQueue';
import { uniqId } from './utils';
import * as dateFormat from 'dateformat';
import { ImmutableTaskList } from './Queue/TaskProvider';
const ID = uniqId();

@ -0,0 +1,23 @@
import { it, describe } from 'mocha';
import { expect } from 'chai';
import { Task } from '../../src/Queue/TaskProvider';
import { TaskQueue } from '../../src/Queue/TaskQueue';
import { NullLogger } from '../../src/Logger';
import { ArrayTaskProvider } from '../../src/Queue/ArrayTaskProvider';
describe('Task Queue', function() {
it('Can get task from queue', function() {
const provider = new ArrayTaskProvider([new Task('1', 0, 'task', {})]);
const queue = new TaskQueue(provider, new NullLogger());
const task = queue.get(1);
expect(task).instanceOf(Task);
});
it("Don't get unready task from queue", function() {
const provider = new ArrayTaskProvider([new Task('1', 5, 'task', {})]);
const queue = new TaskQueue(provider, new NullLogger());
const task = queue.get(1);
expect(task).is.equals(undefined);
});
});