travian/src/Scheduler.ts

111 lines
3.3 KiB
TypeScript

import { markPage, sleepLong, sleepShort } from './utils';
import UpgradeBuildingTask from './Task/UpgradeBuildingTask';
import GoToBuildingAction from './Action/GoToBuildingAction';
import UpgradeBuildingAction from './Action/UpgradeBuildingAction';
import { TryLaterError } from './Errors';
import { TaskQueue, State } from './Storage/TaskQueue';
import ActionQueue from './Storage/ActionQueue';
import { Args, Command } from './Common';
import TaskQueueRenderer from './TaskQueueRenderer';
export default class Scheduler {
taskQueue: TaskQueue;
actionQueue: ActionQueue;
constructor() {
this.taskQueue = new TaskQueue();
this.actionQueue = new ActionQueue();
}
async run() {
await sleepShort();
markPage('Executor');
new TaskQueueRenderer().render(this.taskQueue.state());
while (true) {
await sleepLong();
const actionItem = this.popAction();
this.log('POP ACTION ITEM', actionItem);
if (actionItem !== null) {
const action = this.createAction(actionItem);
this.log('POP ACTION', action);
if (action) {
await this.runAction(action, actionItem.args);
}
} else {
const taskItem = this.popTask();
this.log('POP TASK ITEM', taskItem);
if (taskItem !== null) {
const task = this.createTask(taskItem);
this.log('POP TASK', task);
if (task !== null) {
task.run(taskItem.args);
}
}
}
}
}
pushTask(task: Command): void {
this.log('PUSH TASK', task);
this.taskQueue.push(task);
}
pushAction(action: Command): void {
this.log('PUSH ACTION', action);
this.actionQueue.push(action);
}
scheduleActions(actions: Array<Command>): void {
this.actionQueue.assign(actions);
}
private popTask(): Command | null {
return this.taskQueue.current() || this.taskQueue.next();
}
private createTask(taskItem: Command) {
switch (taskItem.name) {
case UpgradeBuildingTask.NAME:
return new UpgradeBuildingTask(this);
}
this.log('UNKNOWN TASK', taskItem.name);
return null;
}
private popAction() {
const actionItem = this.actionQueue.pop();
if (actionItem === undefined) {
return null;
}
this.log('UNKNOWN ACTION', actionItem.name);
return actionItem;
}
private createAction(actionItem: Command) {
if (actionItem.name === GoToBuildingAction.NAME) {
return new GoToBuildingAction();
}
if (actionItem.name === UpgradeBuildingAction.NAME) {
return new UpgradeBuildingAction();
}
return null;
}
private async runAction(action, args: Args) {
try {
await action.run(args);
} catch (e) {
console.warn('ACTION ERROR', e);
if (e instanceof TryLaterError) {
console.warn('TRY AFTER', e.seconds);
this.actionQueue.clear();
this.taskQueue.postpone(e.seconds);
}
}
}
private log(...args) {
console.log('SCHEDULER:', ...args);
}
}