aboutsummaryrefslogtreecommitdiffstats
path: root/packages/main/src/index.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/main/src/index.ts')
-rw-r--r--packages/main/src/index.ts117
1 files changed, 11 insertions, 106 deletions
diff --git a/packages/main/src/index.ts b/packages/main/src/index.ts
index 8055ce2..8297ff5 100644
--- a/packages/main/src/index.ts
+++ b/packages/main/src/index.ts
@@ -26,20 +26,9 @@ import {
26 nativeTheme, 26 nativeTheme,
27} from 'electron'; 27} from 'electron';
28import { readFileSync } from 'fs'; 28import { readFileSync } from 'fs';
29import { 29import { readFile } from 'fs/promises';
30 readFile,
31 stat,
32 watch,
33 writeFile,
34} from 'fs/promises';
35import JSON5 from 'json5';
36import { autorun } from 'mobx'; 30import { autorun } from 'mobx';
37import { 31import { getSnapshot, onPatch } from 'mobx-state-tree';
38 applySnapshot,
39 getSnapshot,
40 onPatch,
41 onSnapshot,
42} from 'mobx-state-tree';
43import { join } from 'path'; 32import { join } from 'path';
44import { 33import {
45 ServiceToMainIpcMessage, 34 ServiceToMainIpcMessage,
@@ -58,8 +47,8 @@ import {
58 installDevToolsExtensions, 47 installDevToolsExtensions,
59 openDevToolsWhenReady, 48 openDevToolsWhenReady,
60} from './devTools'; 49} from './devTools';
61import { ConfigSnapshotOut } from './stores/Config'; 50import { ConfigPersistenceImpl } from './services/impl/ConfigPersistenceImpl';
62import { createRootStore } from './stores/RootStore'; 51import { createMainStore } from './stores/MainStore';
63 52
64const isDevelopment = import.meta.env.MODE === 'development'; 53const isDevelopment = import.meta.env.MODE === 'development';
65 54
@@ -116,7 +105,12 @@ if (isDevelopment) {
116 105
117let mainWindow: BrowserWindow | null = null; 106let mainWindow: BrowserWindow | null = null;
118 107
119const store = createRootStore(); 108const store = createMainStore({
109 configPersistence: new ConfigPersistenceImpl(
110 app.getPath('userData'),
111 'config.json5',
112 ),
113});
120 114
121autorun(() => { 115autorun(() => {
122 nativeTheme.themeSource = store.config.themeSource; 116 nativeTheme.themeSource = store.config.themeSource;
@@ -127,96 +121,7 @@ nativeTheme.on('updated', () => {
127 store.setShouldUseDarkColors(nativeTheme.shouldUseDarkColors); 121 store.setShouldUseDarkColors(nativeTheme.shouldUseDarkColors);
128}); 122});
129 123
130const userDataDir = app.getPath('userData'); 124store.config.initConfig();
131const configFileName = 'config.json5';
132const configPath = join(userDataDir, configFileName);
133let loadingConfig = false;
134let savingConfig = false;
135let configMtime: Date | null = null;
136
137async function loadConfig(): Promise<void> {
138 let configStr: string;
139 try {
140 configStr = await readFile(configPath, 'utf8');
141 } catch (err) {
142 if ((err as NodeJS.ErrnoException).code === 'ENOENT') {
143 console.log('Creating config', configPath);
144 return saveConfig(getSnapshot(store.config));
145 }
146 throw err;
147 }
148 let configSnapshot: unknown;
149 try {
150 configSnapshot = JSON5.parse(configStr);
151 } catch (err) {
152 console.error('Invalid config file', configPath, err);
153 return;
154 }
155 loadingConfig = true;
156 try {
157 applySnapshot(store.config, configSnapshot);
158 } catch (err) {
159 console.error('Falied to apply snaphot', configPath, configSnapshot, err);
160 } finally {
161 loadingConfig = false;
162 }
163}
164
165async function saveConfig(configSnapshot: ConfigSnapshotOut): Promise<void> {
166 const configJson = JSON5.stringify(configSnapshot, {
167 space: 2,
168 });
169 savingConfig = true;
170 try {
171 await writeFile(configPath, configJson, 'utf8');
172 const stats = await stat(configPath);
173 configMtime = stats.mtime;
174 } finally {
175 savingConfig = false;
176 }
177 console.log('Wrote config', configPath);
178}
179
180onSnapshot(store.config, (snapshot) => {
181 if (!loadingConfig) {
182 saveConfig(snapshot).catch((err) => {
183 console.error('Failed to save config', configPath, err);
184 });
185 }
186});
187
188async function watchConfig(): Promise<void> {
189 const configWatcher = watch(userDataDir, {
190 persistent: false,
191 });
192 for await (const { eventType, filename } of configWatcher) {
193 if (eventType !== 'change'
194 && (filename !== configFileName || filename !== null)) {
195 continue;
196 }
197 let mtime: Date;
198 try {
199 const stats = await stat(configPath);
200 mtime = stats.mtime;
201 } catch (err) {
202 if ((err as NodeJS.ErrnoException).code === 'ENOENT') {
203 continue;
204 }
205 throw err;
206 }
207 if (!savingConfig && (configMtime === null || mtime > configMtime)) {
208 await loadConfig();
209 configMtime = mtime;
210 console.log('Reloaded config', configPath);
211 }
212 }
213}
214
215loadConfig().catch((err) => {
216 console.error('Failed to load config', configPath, err);
217}).then(watchConfig).catch((err) => {
218 console.error('Error when watching for config changes', configPath, err);
219});
220 125
221const rendererBaseUrl = getResourceUrl('../renderer/'); 126const rendererBaseUrl = getResourceUrl('../renderer/');
222function shouldCancelMainWindowRequest(url: string, method: string): boolean { 127function shouldCancelMainWindowRequest(url: string, method: string): boolean {