diff options
author | Kristóf Marussy <kristof@marussy.com> | 2021-12-26 02:43:25 +0100 |
---|---|---|
committer | Kristóf Marussy <kristof@marussy.com> | 2021-12-26 02:43:25 +0100 |
commit | e84a0c57171097eb32ab92e82f54e522b5e1e65f (patch) | |
tree | e6dfb4004d1a32dfca3c116955840986f02e0837 /packages | |
parent | feat: Set nativeTheme theme source on dark mode (diff) | |
download | sophie-e84a0c57171097eb32ab92e82f54e522b5e1e65f.tar.gz sophie-e84a0c57171097eb32ab92e82f54e522b5e1e65f.tar.zst sophie-e84a0c57171097eb32ab92e82f54e522b5e1e65f.zip |
feat: Config persistence
Diffstat (limited to 'packages')
-rw-r--r-- | packages/main/src/index.ts | 93 |
1 files changed, 85 insertions, 8 deletions
diff --git a/packages/main/src/index.ts b/packages/main/src/index.ts index 6a8a74e..a79a6e2 100644 --- a/packages/main/src/index.ts +++ b/packages/main/src/index.ts | |||
@@ -25,9 +25,15 @@ import { | |||
25 | ipcMain, | 25 | ipcMain, |
26 | nativeTheme, | 26 | nativeTheme, |
27 | } from 'electron'; | 27 | } from 'electron'; |
28 | import { readFile, readFileSync } from 'fs'; | 28 | import { readFileSync, watchFile } from 'fs'; |
29 | import { readFile, stat, writeFile } from 'fs/promises'; | ||
29 | import { autorun } from 'mobx'; | 30 | import { autorun } from 'mobx'; |
30 | import { getSnapshot, onPatch } from 'mobx-state-tree'; | 31 | import { |
32 | applySnapshot, | ||
33 | getSnapshot, | ||
34 | onPatch, | ||
35 | onSnapshot, | ||
36 | } from 'mobx-state-tree'; | ||
31 | import { join } from 'path'; | 37 | import { join } from 'path'; |
32 | import { | 38 | import { |
33 | ServiceToMainIpcMessage, | 39 | ServiceToMainIpcMessage, |
@@ -46,6 +52,7 @@ import { | |||
46 | installDevToolsExtensions, | 52 | installDevToolsExtensions, |
47 | openDevToolsWhenReady, | 53 | openDevToolsWhenReady, |
48 | } from './devTools'; | 54 | } from './devTools'; |
55 | import { ConfigSnapshotOut } from './stores/Config'; | ||
49 | import { createRootStore } from './stores/RootStore'; | 56 | import { createRootStore } from './stores/RootStore'; |
50 | 57 | ||
51 | const isDevelopment = import.meta.env.MODE === 'development'; | 58 | const isDevelopment = import.meta.env.MODE === 'development'; |
@@ -114,6 +121,77 @@ nativeTheme.on('updated', () => { | |||
114 | store.setShouldUseDarkColors(nativeTheme.shouldUseDarkColors); | 121 | store.setShouldUseDarkColors(nativeTheme.shouldUseDarkColors); |
115 | }); | 122 | }); |
116 | 123 | ||
124 | const configPath = join(app.getPath('userData'), 'config.json'); | ||
125 | let loadingConfig = false; | ||
126 | let savingConfig = false; | ||
127 | let configMtime: Date | null = null; | ||
128 | |||
129 | async function loadConfig(): Promise<void> { | ||
130 | let configStr: string; | ||
131 | try { | ||
132 | configStr = await readFile(configPath, 'utf8'); | ||
133 | } catch (err) { | ||
134 | if ((err as NodeJS.ErrnoException).code === 'ENOENT') { | ||
135 | console.log('Creating config', configPath); | ||
136 | return saveConfig(getSnapshot(store.config)); | ||
137 | } | ||
138 | throw err; | ||
139 | } | ||
140 | let configSnapshot: unknown; | ||
141 | try { | ||
142 | configSnapshot = JSON.parse(configStr); | ||
143 | } catch (err) { | ||
144 | console.error('Invalid config file', configPath, err); | ||
145 | return; | ||
146 | } | ||
147 | loadingConfig = true; | ||
148 | try { | ||
149 | applySnapshot(store.config, configSnapshot); | ||
150 | } catch (err) { | ||
151 | console.error('Falied to apply snaphot', configPath, configSnapshot, err); | ||
152 | } finally { | ||
153 | loadingConfig = false; | ||
154 | } | ||
155 | } | ||
156 | |||
157 | async function saveConfig(configSnapshot: ConfigSnapshotOut): Promise<void> { | ||
158 | const configJson = JSON.stringify(configSnapshot, null, 2); | ||
159 | savingConfig = true; | ||
160 | try { | ||
161 | await writeFile(configPath, configJson, 'utf8'); | ||
162 | const stats = await stat(configPath); | ||
163 | configMtime = stats.mtime; | ||
164 | } finally { | ||
165 | savingConfig = false; | ||
166 | } | ||
167 | console.log('Wrote config', configPath); | ||
168 | } | ||
169 | |||
170 | onSnapshot(store.config, (snapshot) => { | ||
171 | if (!loadingConfig) { | ||
172 | saveConfig(snapshot).catch((err) => { | ||
173 | console.error('Failed to save config', configPath, err); | ||
174 | }); | ||
175 | } | ||
176 | }); | ||
177 | |||
178 | async function initializeConfig(): Promise<void> { | ||
179 | await loadConfig(); | ||
180 | watchFile(configPath, ({ mtime }) => { | ||
181 | if (!savingConfig && (configMtime === null || mtime > configMtime)) { | ||
182 | loadConfig().catch((err) => { | ||
183 | console.error('Failed to reload config', configPath, err); | ||
184 | }); | ||
185 | configMtime = mtime; | ||
186 | console.log('Reloaded config', configPath); | ||
187 | } | ||
188 | }); | ||
189 | } | ||
190 | |||
191 | initializeConfig().catch((err) => { | ||
192 | console.error('Failed to load config', configPath, err); | ||
193 | }); | ||
194 | |||
117 | const rendererBaseUrl = getResourceUrl('../renderer/'); | 195 | const rendererBaseUrl = getResourceUrl('../renderer/'); |
118 | function shouldCancelMainWindowRequest(url: string, method: string): boolean { | 196 | function shouldCancelMainWindowRequest(url: string, method: string): boolean { |
119 | if (method !== 'GET') { | 197 | if (method !== 'GET') { |
@@ -205,12 +283,11 @@ function createWindow(): Promise<unknown> { | |||
205 | store.config.setThemeSource(themeSource.parse(args[0])) | 283 | store.config.setThemeSource(themeSource.parse(args[0])) |
206 | break; | 284 | break; |
207 | case RendererToMainIpcMessage.ReloadAllServices: | 285 | case RendererToMainIpcMessage.ReloadAllServices: |
208 | readFile(serviceInjectPath, 'utf8', (err, data) => { | 286 | readFile(serviceInjectPath, 'utf8').then((data) => { |
209 | if (err === null) { | 287 | serviceInject.code = data; |
210 | serviceInject.code = data; | 288 | }).catch((err) => { |
211 | } else { | 289 | console.error('Error while reloading', serviceInjectPath, err); |
212 | console.error('Error while reloading', serviceInjectPath, err); | 290 | }).then(() => { |
213 | } | ||
214 | browserView.webContents.reload(); | 291 | browserView.webContents.reload(); |
215 | }); | 292 | }); |
216 | break; | 293 | break; |