mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-01-11 16:39:15 +08:00
fix: flush redux persist data when app quit and update (#8741)
* feat(database): enable strict transaction durability for CherryStudio database - Updated the Dexie database initialization to include `chromeTransactionDurability: 'strict'`, enhancing data integrity during transactions. * feat(app): enhance application shutdown process and data flushing - Added functionality to flush storage data and cookies before quitting the application, ensuring data integrity. - Introduced a new `handleBeforeQuit` function to centralize cleanup logic for both manual and update-triggered quits. - Updated logging to provide better insights during the shutdown process. - Modified ProxyManager to use debug level for unchanged proxy configurations. - Added `persistor` to the global window object and implemented `handleSaveData` to flush Redux state before quitting. * format code * feat(ipc): add App_SaveData channel and implement data saving on window close - Introduced a new IPC channel `App_SaveData` for saving application data. - Updated `WindowService` to send a save data message when the main window is closed. - Enhanced `useAppInit` hook to handle the `App_SaveData` event and trigger data saving logic. * refactor(env): remove persistor from global window object - Removed the `persistor` property from the global `window` object in both `env.d.ts` and `index.ts` files, streamlining the application state management.
This commit is contained in:
parent
b7394c98a4
commit
488a01d7d7
@ -34,6 +34,7 @@ export enum IpcChannel {
|
|||||||
App_InstallUvBinary = 'app:install-uv-binary',
|
App_InstallUvBinary = 'app:install-uv-binary',
|
||||||
App_InstallBunBinary = 'app:install-bun-binary',
|
App_InstallBunBinary = 'app:install-bun-binary',
|
||||||
App_LogToMain = 'app:log-to-main',
|
App_LogToMain = 'app:log-to-main',
|
||||||
|
App_SaveData = 'app:save-data',
|
||||||
|
|
||||||
App_MacIsProcessTrusted = 'app:mac-is-process-trusted',
|
App_MacIsProcessTrusted = 'app:mac-is-process-trusted',
|
||||||
App_MacRequestProcessTrust = 'app:mac-request-process-trust',
|
App_MacRequestProcessTrust = 'app:mac-request-process-trust',
|
||||||
|
|||||||
@ -66,7 +66,7 @@ export class ProxyManager {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (config?.mode === this.config?.mode && config?.proxyRules === this.config?.proxyRules) {
|
if (config?.mode === this.config?.mode && config?.proxyRules === this.config?.proxyRules) {
|
||||||
logger.info('proxy config is the same, skip configure')
|
logger.debug('proxy config is the same, skip configure')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -319,6 +319,13 @@ export class WindowService {
|
|||||||
|
|
||||||
private setupWindowLifecycleEvents(mainWindow: BrowserWindow) {
|
private setupWindowLifecycleEvents(mainWindow: BrowserWindow) {
|
||||||
mainWindow.on('close', (event) => {
|
mainWindow.on('close', (event) => {
|
||||||
|
// save data before when close window
|
||||||
|
try {
|
||||||
|
mainWindow.webContents.send(IpcChannel.App_SaveData)
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('Failed to save data:', error as Error)
|
||||||
|
}
|
||||||
|
|
||||||
// 如果已经触发退出,直接退出
|
// 如果已经触发退出,直接退出
|
||||||
if (app.isQuitting) {
|
if (app.isQuitting) {
|
||||||
return app.quit()
|
return app.quit()
|
||||||
|
|||||||
@ -8,10 +8,12 @@ import KnowledgeQueue from '@renderer/queue/KnowledgeQueue'
|
|||||||
import MemoryService from '@renderer/services/MemoryService'
|
import MemoryService from '@renderer/services/MemoryService'
|
||||||
import { useAppDispatch } from '@renderer/store'
|
import { useAppDispatch } from '@renderer/store'
|
||||||
import { useAppSelector } from '@renderer/store'
|
import { useAppSelector } from '@renderer/store'
|
||||||
|
import { handleSaveData } from '@renderer/store'
|
||||||
import { selectMemoryConfig } from '@renderer/store/memory'
|
import { selectMemoryConfig } from '@renderer/store/memory'
|
||||||
import { setAvatar, setFilesPath, setResourcesPath, setUpdateState } from '@renderer/store/runtime'
|
import { setAvatar, setFilesPath, setResourcesPath, setUpdateState } from '@renderer/store/runtime'
|
||||||
import { delay, runAsyncFunction } from '@renderer/utils'
|
import { delay, runAsyncFunction } from '@renderer/utils'
|
||||||
import { defaultLanguage } from '@shared/config/constant'
|
import { defaultLanguage } from '@shared/config/constant'
|
||||||
|
import { IpcChannel } from '@shared/IpcChannel'
|
||||||
import { useLiveQuery } from 'dexie-react-hooks'
|
import { useLiveQuery } from 'dexie-react-hooks'
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
|
|
||||||
@ -49,6 +51,12 @@ export function useAppInit() {
|
|||||||
})
|
})
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
window.electron.ipcRenderer.on(IpcChannel.App_SaveData, async () => {
|
||||||
|
await handleSaveData()
|
||||||
|
})
|
||||||
|
}, [])
|
||||||
|
|
||||||
useUpdateHandler()
|
useUpdateHandler()
|
||||||
useFullScreenNotice()
|
useFullScreenNotice()
|
||||||
|
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import { useMinappPopup } from '@renderer/hooks/useMinappPopup'
|
|||||||
import { useRuntime } from '@renderer/hooks/useRuntime'
|
import { useRuntime } from '@renderer/hooks/useRuntime'
|
||||||
import { useSettings } from '@renderer/hooks/useSettings'
|
import { useSettings } from '@renderer/hooks/useSettings'
|
||||||
import i18n from '@renderer/i18n'
|
import i18n from '@renderer/i18n'
|
||||||
import { useAppDispatch } from '@renderer/store'
|
import { handleSaveData, useAppDispatch } from '@renderer/store'
|
||||||
import { setUpdateState } from '@renderer/store/runtime'
|
import { setUpdateState } from '@renderer/store/runtime'
|
||||||
import { ThemeMode } from '@renderer/types'
|
import { ThemeMode } from '@renderer/types'
|
||||||
import { runAsyncFunction } from '@renderer/utils'
|
import { runAsyncFunction } from '@renderer/utils'
|
||||||
@ -41,6 +41,7 @@ const AboutSettings: FC = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (update.downloaded) {
|
if (update.downloaded) {
|
||||||
|
await handleSaveData()
|
||||||
window.api.showUpdateDialog()
|
window.api.showUpdateDialog()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { combineReducers, configureStore } from '@reduxjs/toolkit'
|
import { combineReducers, configureStore } from '@reduxjs/toolkit'
|
||||||
|
import { loggerService } from '@renderer/services/LoggerService'
|
||||||
import { useDispatch, useSelector, useStore } from 'react-redux'
|
import { useDispatch, useSelector, useStore } from 'react-redux'
|
||||||
import { FLUSH, PAUSE, PERSIST, persistReducer, persistStore, PURGE, REGISTER, REHYDRATE } from 'redux-persist'
|
import { FLUSH, PAUSE, PERSIST, persistReducer, persistStore, PURGE, REGISTER, REHYDRATE } from 'redux-persist'
|
||||||
import storage from 'redux-persist/lib/storage'
|
import storage from 'redux-persist/lib/storage'
|
||||||
@ -28,6 +29,8 @@ import tabs from './tabs'
|
|||||||
import translate from './translate'
|
import translate from './translate'
|
||||||
import websearch from './websearch'
|
import websearch from './websearch'
|
||||||
|
|
||||||
|
const logger = loggerService.withContext('Store')
|
||||||
|
|
||||||
const rootReducer = combineReducers({
|
const rootReducer = combineReducers({
|
||||||
assistants,
|
assistants,
|
||||||
agents,
|
agents,
|
||||||
@ -101,4 +104,10 @@ export const useAppSelector = useSelector.withTypes<RootState>()
|
|||||||
export const useAppStore = useStore.withTypes<typeof store>()
|
export const useAppStore = useStore.withTypes<typeof store>()
|
||||||
window.store = store
|
window.store = store
|
||||||
|
|
||||||
|
export async function handleSaveData() {
|
||||||
|
logger.info('Flushing redux persistor data')
|
||||||
|
await persistor.flush()
|
||||||
|
logger.info('Flushed redux persistor data')
|
||||||
|
}
|
||||||
|
|
||||||
export default store
|
export default store
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user