From 21c773961bee82bddfcc755deba15cf210d045a5 Mon Sep 17 00:00:00 2001
From: Anton Vakhrushev <anwinged@ya.ru>
Date: Mon, 27 Apr 2020 21:44:27 +0300
Subject: [PATCH] Add pause feature

---
 src/ControlPanel.ts            | 12 +++++++++++-
 src/DashboardView/Header.vue   |  8 ++++++++
 src/DashboardView/TaskList.vue |  1 +
 src/Executor.ts                | 13 +++++++++++++
 src/State/ExecutionState.ts    | 23 +++++++++++++++++++++++
 5 files changed, 56 insertions(+), 1 deletion(-)
 create mode 100644 src/State/ExecutionState.ts

diff --git a/src/ControlPanel.ts b/src/ControlPanel.ts
index 5e2e061..7f3a317 100644
--- a/src/ControlPanel.ts
+++ b/src/ControlPanel.ts
@@ -1,4 +1,4 @@
-import { parseLocation, uniqId, waitForLoad } from './utils';
+import { parseLocation, timestamp, uniqId, waitForLoad } from './utils';
 import { Scheduler } from './Scheduler';
 import { BuildingPageController } from './Page/BuildingPageController';
 import { UpgradeBuildingTask } from './Task/UpgradeBuildingTask';
@@ -20,6 +20,7 @@ import { calcGatheringTimings } from './Core/GatheringTimings';
 import { DataStorage } from './DataStorage';
 import { getBuildingPageAttributes, isBuildingPage } from './Page/PageDetectors';
 import { debounce } from 'debounce';
+import { ExecutionState } from './State/ExecutionState';
 
 interface QuickAction {
     label: string;
@@ -48,6 +49,8 @@ export class ControlPanel {
         const scheduler = this.scheduler;
         const quickActions: QuickAction[] = [];
 
+        const executionState = new ExecutionState();
+
         const state = {
             name: 'Dashboard',
             version: this.version,
@@ -56,10 +59,13 @@ export class ControlPanel {
             taskList: [],
             actionList: [],
             quickActions: quickActions,
+            pauseSeconds: 0,
 
             refresh() {
                 this.taskList = scheduler.getTaskItems();
                 this.actionList = scheduler.getActionItems();
+                const { pauseTs } = executionState.getExecutionSettings();
+                this.pauseSeconds = pauseTs - timestamp();
                 this.refreshVillages();
             },
 
@@ -78,6 +84,10 @@ export class ControlPanel {
                     }
                 }
             },
+
+            pause() {
+                executionState.setExecutionSettings({ pauseTs: timestamp() + 120 });
+            },
         };
 
         state.refresh();
diff --git a/src/DashboardView/Header.vue b/src/DashboardView/Header.vue
index 6a29bea..c5b0597 100644
--- a/src/DashboardView/Header.vue
+++ b/src/DashboardView/Header.vue
@@ -3,6 +3,9 @@
     <h1 class="title">
       [{{ shared.name }}] {{ villageName }}
       <span class="version">- {{ shared.version }}</span>
+      <a href="#" v-on:click.prevent="pause()">
+        pause <span v-if="shared.pauseSeconds" v-text="shared.pauseSeconds"></span>
+      </a>
     </h1>
   </section>
 </template>
@@ -20,6 +23,11 @@ export default {
       return village ? village.name : 'Unknown';
     },
   },
+  methods: {
+    pause() {
+      this.shared.pause();
+    },
+  },
 };
 </script>
 
diff --git a/src/DashboardView/TaskList.vue b/src/DashboardView/TaskList.vue
index d9caab4..ebba85f 100644
--- a/src/DashboardView/TaskList.vue
+++ b/src/DashboardView/TaskList.vue
@@ -25,6 +25,7 @@
 
 <script>
 import * as dateFormat from 'dateformat';
+import { timestamp } from '../utils';
 
 export default {
   data() {
diff --git a/src/Executor.ts b/src/Executor.ts
index 98430b4..8d7de4f 100644
--- a/src/Executor.ts
+++ b/src/Executor.ts
@@ -9,12 +9,18 @@ import { ConsoleLogger, Logger } from './Logger';
 import { GrabberManager } from './Grabber/GrabberManager';
 import { Scheduler } from './Scheduler';
 import { Statistics } from './Statistics';
+import { ExecutionState } from './State/ExecutionState';
+
+export interface ExecutionSettings {
+    pauseTs: number;
+}
 
 export class Executor {
     private readonly version: string;
     private readonly scheduler: Scheduler;
     private grabbers: GrabberManager;
     private statistics: Statistics;
+    private executionState: ExecutionState;
     private logger: Logger;
 
     constructor(version: string, scheduler: Scheduler) {
@@ -22,6 +28,7 @@ export class Executor {
         this.scheduler = scheduler;
         this.grabbers = new GrabberManager();
         this.statistics = new Statistics();
+        this.executionState = new ExecutionState();
         this.logger = new ConsoleLogger(this.constructor.name);
     }
 
@@ -44,6 +51,12 @@ export class Executor {
             } else {
                 await sleepMicro();
             }
+
+            const { pauseTs } = this.executionState.getExecutionSettings();
+            if (pauseTs > timestamp()) {
+                continue;
+            }
+
             await this.doTaskProcessingStep();
         }
     }
diff --git a/src/State/ExecutionState.ts b/src/State/ExecutionState.ts
new file mode 100644
index 0000000..98e5508
--- /dev/null
+++ b/src/State/ExecutionState.ts
@@ -0,0 +1,23 @@
+import { DataStorage } from '../DataStorage';
+import { ExecutionSettings } from '../Executor';
+
+const NAMESPACE = 'execution.v1';
+
+const SETTINGS_KEY = 'settings';
+
+export class ExecutionState {
+    private storage: DataStorage;
+    constructor() {
+        this.storage = new DataStorage(NAMESPACE);
+    }
+
+    getExecutionSettings(): ExecutionSettings {
+        return this.storage.getTyped<ExecutionSettings>(SETTINGS_KEY, {
+            factory: () => ({ pauseTs: 0 }),
+        });
+    }
+
+    setExecutionSettings(statistics: ExecutionSettings): void {
+        this.storage.set(SETTINGS_KEY, statistics);
+    }
+}