aboutsummaryrefslogtreecommitdiffstats
path: root/packages/main/src/controllers/ConfigController.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/main/src/controllers/ConfigController.ts')
-rw-r--r--packages/main/src/controllers/ConfigController.ts105
1 files changed, 44 insertions, 61 deletions
diff --git a/packages/main/src/controllers/ConfigController.ts b/packages/main/src/controllers/ConfigController.ts
index 6690548..a28746c 100644
--- a/packages/main/src/controllers/ConfigController.ts
+++ b/packages/main/src/controllers/ConfigController.ts
@@ -25,56 +25,62 @@ import {
25 IDisposer, 25 IDisposer,
26 onSnapshot, 26 onSnapshot,
27} from 'mobx-state-tree'; 27} from 'mobx-state-tree';
28import ms from 'ms';
29 28
30import { ConfigPersistenceService } from '../services/ConfigPersistenceService'; 29import type { ConfigPersistenceService } from '../services/ConfigPersistenceService';
31import { Config, ConfigSnapshotOut } from '../stores/Config'; 30import type { Config, ConfigSnapshotOut } from '../stores/Config';
32 31
33const DEFAULT_DEBOUNCE_TIME = ms('1s'); 32export class ConfigController {
33 static inject = ['configPersistenceService', 'configDebounceTime'] as const;
34 34
35class ConfigController { 35 private config: Config | null = null;
36 readonly #config: Config;
37 36
38 readonly #persistenceService: ConfigPersistenceService; 37 private onSnapshotDisposer: IDisposer | null = null;
39 38
40 readonly #onSnapshotDisposer: IDisposer; 39 private lastSnapshotOnDisk: ConfigSnapshotOut | null = null;
41 40
42 readonly #watcherDisposer: IDisposer; 41 private writingConfig: boolean = false;
43 42
44 #lastSnapshotOnDisk: ConfigSnapshotOut | null = null; 43 constructor(
44 private readonly persistenceService: ConfigPersistenceService,
45 private readonly debounceTime: number,
46 ) {
47 }
45 48
46 #writingConfig: boolean = false; 49 async initConfig(config: Config): Promise<void> {
50 this.config = config;
47 51
48 #configMTime: Date | null = null; 52 const foundConfig: boolean = await this.readConfig();
53 if (!foundConfig) {
54 console.log('Creating new config file');
55 try {
56 await this.writeConfig();
57 } catch (err) {
58 console.error('Failed to initialize config');
59 }
60 }
49 61
50 constructor( 62 this.onSnapshotDisposer = onSnapshot(this.config, debounce((snapshot) => {
51 config: Config,
52 persistenceService: ConfigPersistenceService,
53 debounceTime: number,
54 ) {
55 this.#config = config;
56 this.#persistenceService = persistenceService;
57 this.#onSnapshotDisposer = onSnapshot(this.#config, debounce((snapshot) => {
58 // We can compare snapshots by reference, since it is only recreated on store changes. 63 // We can compare snapshots by reference, since it is only recreated on store changes.
59 if (this.#lastSnapshotOnDisk !== snapshot) { 64 if (this.lastSnapshotOnDisk !== snapshot) {
60 this.#writeConfig().catch((err) => { 65 this.writeConfig().catch((err) => {
61 console.log('Failed to write config on config change', err); 66 console.log('Failed to write config on config change', err);
62 }) 67 })
63 } 68 }
64 }, debounceTime)); 69 }, this.debounceTime));
65 this.#watcherDisposer = this.#persistenceService.watchConfig(async (mtime) => { 70
66 if (!this.#writingConfig && (this.#configMTime === null || mtime > this.#configMTime)) { 71 this.persistenceService.watchConfig(async () => {
67 await this.#readConfig(); 72 if (!this.writingConfig) {
73 await this.readConfig();
68 } 74 }
69 }, debounceTime); 75 }, this.debounceTime);
70 } 76 }
71 77
72 async #readConfig(): Promise<boolean> { 78 private async readConfig(): Promise<boolean> {
73 const result = await this.#persistenceService.readConfig(); 79 const result = await this.persistenceService.readConfig();
74 if (result.found) { 80 if (result.found) {
75 try { 81 try {
76 applySnapshot(this.#config, result.data); 82 applySnapshot(this.config!, result.data);
77 this.#lastSnapshotOnDisk = getSnapshot(this.#config); 83 this.lastSnapshotOnDisk = getSnapshot(this.config!);
78 console.log('Loaded config'); 84 console.log('Loaded config');
79 } catch (err) { 85 } catch (err) {
80 console.error('Failed to read config', result.data, err); 86 console.error('Failed to read config', result.data, err);
@@ -83,42 +89,19 @@ class ConfigController {
83 return result.found; 89 return result.found;
84 } 90 }
85 91
86 async #writeConfig(): Promise<void> { 92 private async writeConfig(): Promise<void> {
87 const snapshot = getSnapshot(this.#config); 93 const snapshot = getSnapshot(this.config!);
88 this.#writingConfig = true; 94 this.writingConfig = true;
89 try { 95 try {
90 this.#configMTime = await this.#persistenceService.writeConfig(snapshot); 96 await this.persistenceService.writeConfig(snapshot);
91 this.#lastSnapshotOnDisk = snapshot; 97 this.lastSnapshotOnDisk = snapshot;
92 console.log('Wrote config'); 98 console.log('Wrote config');
93 } finally { 99 } finally {
94 this.#writingConfig = false; 100 this.writingConfig = false;
95 }
96 }
97
98 async initConfig(): Promise<void> {
99 const foundConfig: boolean = await this.#readConfig();
100 if (!foundConfig) {
101 console.log('Creating new config file');
102 try {
103 await this.#writeConfig();
104 } catch (err) {
105 console.error('Failed to initialize config');
106 }
107 } 101 }
108 } 102 }
109 103
110 dispose(): void { 104 dispose(): void {
111 this.#onSnapshotDisposer(); 105 this.onSnapshotDisposer?.();
112 this.#watcherDisposer();
113 } 106 }
114} 107}
115
116export async function initConfig(
117 config: Config,
118 persistenceService: ConfigPersistenceService,
119 debounceTime: number = DEFAULT_DEBOUNCE_TIME,
120): Promise<IDisposer> {
121 const controller = new ConfigController(config, persistenceService, debounceTime);
122 await controller.initConfig();
123 return () => controller.dispose();
124}