diff options
Diffstat (limited to 'packages/main/src/index.ts')
-rw-r--r-- | packages/main/src/index.ts | 117 |
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'; |
28 | import { readFileSync } from 'fs'; | 28 | import { readFileSync } from 'fs'; |
29 | import { | 29 | import { readFile } from 'fs/promises'; |
30 | readFile, | ||
31 | stat, | ||
32 | watch, | ||
33 | writeFile, | ||
34 | } from 'fs/promises'; | ||
35 | import JSON5 from 'json5'; | ||
36 | import { autorun } from 'mobx'; | 30 | import { autorun } from 'mobx'; |
37 | import { | 31 | import { getSnapshot, onPatch } from 'mobx-state-tree'; |
38 | applySnapshot, | ||
39 | getSnapshot, | ||
40 | onPatch, | ||
41 | onSnapshot, | ||
42 | } from 'mobx-state-tree'; | ||
43 | import { join } from 'path'; | 32 | import { join } from 'path'; |
44 | import { | 33 | import { |
45 | ServiceToMainIpcMessage, | 34 | ServiceToMainIpcMessage, |
@@ -58,8 +47,8 @@ import { | |||
58 | installDevToolsExtensions, | 47 | installDevToolsExtensions, |
59 | openDevToolsWhenReady, | 48 | openDevToolsWhenReady, |
60 | } from './devTools'; | 49 | } from './devTools'; |
61 | import { ConfigSnapshotOut } from './stores/Config'; | 50 | import { ConfigPersistenceImpl } from './services/impl/ConfigPersistenceImpl'; |
62 | import { createRootStore } from './stores/RootStore'; | 51 | import { createMainStore } from './stores/MainStore'; |
63 | 52 | ||
64 | const isDevelopment = import.meta.env.MODE === 'development'; | 53 | const isDevelopment = import.meta.env.MODE === 'development'; |
65 | 54 | ||
@@ -116,7 +105,12 @@ if (isDevelopment) { | |||
116 | 105 | ||
117 | let mainWindow: BrowserWindow | null = null; | 106 | let mainWindow: BrowserWindow | null = null; |
118 | 107 | ||
119 | const store = createRootStore(); | 108 | const store = createMainStore({ |
109 | configPersistence: new ConfigPersistenceImpl( | ||
110 | app.getPath('userData'), | ||
111 | 'config.json5', | ||
112 | ), | ||
113 | }); | ||
120 | 114 | ||
121 | autorun(() => { | 115 | autorun(() => { |
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 | ||
130 | const userDataDir = app.getPath('userData'); | 124 | store.config.initConfig(); |
131 | const configFileName = 'config.json5'; | ||
132 | const configPath = join(userDataDir, configFileName); | ||
133 | let loadingConfig = false; | ||
134 | let savingConfig = false; | ||
135 | let configMtime: Date | null = null; | ||
136 | |||
137 | async 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 | |||
165 | async 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 | |||
180 | onSnapshot(store.config, (snapshot) => { | ||
181 | if (!loadingConfig) { | ||
182 | saveConfig(snapshot).catch((err) => { | ||
183 | console.error('Failed to save config', configPath, err); | ||
184 | }); | ||
185 | } | ||
186 | }); | ||
187 | |||
188 | async 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 | |||
215 | loadConfig().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 | ||
221 | const rendererBaseUrl = getResourceUrl('../renderer/'); | 126 | const rendererBaseUrl = getResourceUrl('../renderer/'); |
222 | function shouldCancelMainWindowRequest(url: string, method: string): boolean { | 127 | function shouldCancelMainWindowRequest(url: string, method: string): boolean { |