@lobehub/lobehub 2.0.0-next.163 → 2.0.0-next.165
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cursor/rules/desktop-feature-implementation.mdc +31 -34
- package/.cursor/rules/desktop-local-tools-implement.mdc +3 -3
- package/.cursor/rules/desktop-window-management.mdc +56 -66
- package/CHANGELOG.md +52 -0
- package/README.md +6 -6
- package/README.zh-CN.md +6 -6
- package/apps/desktop/Development.md +42 -46
- package/apps/desktop/README.md +37 -1
- package/apps/desktop/README.zh-CN.md +26 -1
- package/apps/desktop/electron.vite.config.ts +1 -0
- package/apps/desktop/src/main/controllers/AuthCtr.ts +4 -3
- package/apps/desktop/src/main/controllers/BrowserWindowsCtr.ts +33 -20
- package/apps/desktop/src/main/controllers/DevtoolsCtr.ts +4 -2
- package/apps/desktop/src/main/controllers/LocalFileCtr.ts +14 -13
- package/apps/desktop/src/main/controllers/MenuCtr.ts +5 -4
- package/apps/desktop/src/main/controllers/NetworkProxyCtr.ts +18 -19
- package/apps/desktop/src/main/controllers/NotificationCtr.ts +4 -3
- package/apps/desktop/src/main/controllers/RemoteServerConfigCtr.ts +5 -4
- package/apps/desktop/src/main/controllers/RemoteServerSyncCtr.ts +3 -2
- package/apps/desktop/src/main/controllers/ShellCommandCtr.ts +5 -4
- package/apps/desktop/src/main/controllers/ShortcutCtr.ts +4 -3
- package/apps/desktop/src/main/controllers/SystemCtr.ts +7 -37
- package/apps/desktop/src/main/controllers/SystemServerCtr.ts +38 -0
- package/apps/desktop/src/main/controllers/TrayMenuCtr.ts +5 -4
- package/apps/desktop/src/main/controllers/UpdaterCtr.ts +6 -5
- package/apps/desktop/src/main/controllers/UploadFileCtr.ts +3 -25
- package/apps/desktop/src/main/controllers/UploadFileServerCtr.ts +33 -0
- package/apps/desktop/src/main/controllers/__tests__/AuthCtr.test.ts +9 -1
- package/apps/desktop/src/main/controllers/__tests__/BrowserWindowsCtr.test.ts +29 -9
- package/apps/desktop/src/main/controllers/__tests__/DevtoolsCtr.test.ts +12 -3
- package/apps/desktop/src/main/controllers/__tests__/LocalFileCtr.test.ts +7 -0
- package/apps/desktop/src/main/controllers/__tests__/MenuCtr.test.ts +10 -0
- package/apps/desktop/src/main/controllers/__tests__/NetworkProxyCtr.test.ts +10 -0
- package/apps/desktop/src/main/controllers/__tests__/NotificationCtr.test.ts +8 -0
- package/apps/desktop/src/main/controllers/__tests__/RemoteServerConfigCtr.test.ts +8 -0
- package/apps/desktop/src/main/controllers/__tests__/RemoteServerSyncCtr.test.ts +1 -0
- package/apps/desktop/src/main/controllers/__tests__/ShellCommandCtr.test.ts +10 -0
- package/apps/desktop/src/main/controllers/__tests__/ShortcutCtr.test.ts +11 -0
- package/apps/desktop/src/main/controllers/__tests__/SystemCtr.test.ts +43 -73
- package/apps/desktop/src/main/controllers/__tests__/SystemServerCtr.test.ts +75 -0
- package/apps/desktop/src/main/controllers/__tests__/TrayMenuCtr.test.ts +24 -13
- package/apps/desktop/src/main/controllers/__tests__/UpdaterCtr.test.ts +13 -2
- package/apps/desktop/src/main/controllers/__tests__/UploadFileCtr.test.ts +29 -108
- package/apps/desktop/src/main/controllers/__tests__/UploadFileServerCtr.test.ts +55 -0
- package/apps/desktop/src/main/controllers/_template.ts +2 -2
- package/apps/desktop/src/main/controllers/index.ts +5 -29
- package/apps/desktop/src/main/controllers/registry.ts +52 -0
- package/apps/desktop/src/main/core/App.ts +15 -47
- package/apps/desktop/src/main/core/__tests__/App.test.ts +5 -4
- package/apps/desktop/src/main/core/infrastructure/IoCContainer.ts +0 -5
- package/apps/desktop/src/main/core/infrastructure/__tests__/IoCContainer.test.ts +0 -50
- package/apps/desktop/src/main/exports.d.ts +8 -0
- package/apps/desktop/src/main/exports.ts +2 -0
- package/apps/desktop/src/main/global.d.ts +3 -0
- package/apps/desktop/src/main/modules/fileSearch/__tests__/macOS.integration.test.ts +17 -8
- package/apps/desktop/src/main/package.json +10 -0
- package/apps/desktop/src/main/services/fileSrv.ts +1 -1
- package/apps/desktop/src/main/utils/ipc/__tests__/base.test.ts +91 -0
- package/apps/desktop/src/main/utils/ipc/base.ts +170 -0
- package/apps/desktop/src/main/utils/ipc/index.ts +11 -0
- package/apps/desktop/src/main/utils/ipc/utility.ts +20 -0
- package/apps/desktop/src/preload/electronApi.ts +4 -1
- package/apps/desktop/src/preload/invoke.test.ts +13 -16
- package/apps/desktop/src/preload/invoke.ts +2 -5
- package/apps/desktop/src/preload/routeInterceptor.test.ts +13 -13
- package/apps/desktop/src/preload/routeInterceptor.ts +4 -4
- package/apps/desktop/tsconfig.json +15 -5
- package/changelog/v1.json +14 -0
- package/locales/ar/auth.json +3 -0
- package/locales/bg-BG/auth.json +3 -0
- package/locales/de-DE/auth.json +3 -0
- package/locales/en-US/auth.json +4 -1
- package/locales/es-ES/auth.json +3 -0
- package/locales/fa-IR/auth.json +3 -0
- package/locales/fr-FR/auth.json +3 -0
- package/locales/it-IT/auth.json +3 -0
- package/locales/ja-JP/auth.json +3 -0
- package/locales/ko-KR/auth.json +3 -0
- package/locales/nl-NL/auth.json +3 -0
- package/locales/pl-PL/auth.json +3 -0
- package/locales/pt-BR/auth.json +3 -0
- package/locales/ru-RU/auth.json +3 -0
- package/locales/tr-TR/auth.json +3 -0
- package/locales/vi-VN/auth.json +3 -0
- package/locales/zh-CN/auth.json +3 -0
- package/locales/zh-TW/auth.json +3 -0
- package/package.json +4 -3
- package/packages/electron-client-ipc/src/index.ts +1 -1
- package/packages/electron-client-ipc/src/ipc.test.ts +62 -0
- package/packages/electron-client-ipc/src/ipc.ts +63 -0
- package/packages/electron-client-ipc/src/streamInvoke.ts +7 -1
- package/packages/electron-client-ipc/src/types/dispatch.ts +1 -10
- package/packages/electron-client-ipc/vitest.config.mts +10 -0
- package/packages/electron-server-ipc/src/ipcClient.ts +1 -2
- package/packages/electron-server-ipc/src/ipcServer.ts +1 -2
- package/packages/electron-server-ipc/src/types/index.ts +1 -5
- package/pnpm-workspace.yaml +1 -1
- package/scripts/i18nWorkflow/const.ts +2 -2
- package/scripts/i18nWorkflow/i18nConfig.ts +7 -0
- package/scripts/i18nWorkflow/utils.ts +1 -1
- package/src/app/[variants]/(auth)/signup/[[...signup]]/BetterAuthSignUpForm.tsx +23 -0
- package/src/app/[variants]/(main)/(mobile)/me/(home)/features/UserBanner.tsx +3 -9
- package/src/app/[variants]/(main)/discover/(detail)/provider/features/Sidebar/ActionButton/ProviderConfig.tsx +2 -2
- package/src/app/[variants]/(main)/profile/(home)/Client.tsx +206 -138
- package/src/features/User/PlanTag.tsx +4 -4
- package/src/locales/default/auth.ts +3 -0
- package/src/locales/default/setting.ts +1 -0
- package/src/server/modules/ElectronIPCClient/index.ts +59 -13
- package/src/services/electron/__tests__/devtools.test.ts +10 -6
- package/src/services/electron/autoUpdate.ts +5 -5
- package/src/services/electron/desktopNotification.ts +4 -7
- package/src/services/electron/devtools.ts +2 -2
- package/src/services/electron/file.ts +3 -2
- package/src/services/electron/localFileService.ts +17 -16
- package/src/services/electron/remoteServer.ts +7 -6
- package/src/services/electron/settings.ts +9 -11
- package/src/services/electron/system.ts +8 -6
- package/src/store/chat/slices/plugin/actions/pluginTypes.ts +1 -1
- package/src/store/global/actions/general.ts +8 -10
- package/src/utils/electron/desktopRemoteRPCFetch.ts +3 -2
- package/src/utils/electron/ipc.ts +12 -0
- package/tsconfig.json +5 -0
- package/apps/desktop/src/main/types/ipcClientEvent.ts +0 -3
- package/packages/electron-client-ipc/src/dispatch.ts +0 -41
|
@@ -1,22 +1,21 @@
|
|
|
1
1
|
import { InterceptRouteParams, OpenSettingsWindowOptions } from '@lobechat/electron-client-ipc';
|
|
2
2
|
import { findMatchingRoute } from '~common/routes';
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
WindowTemplateIdentifiers,
|
|
7
|
-
} from '@/appBrowsers';
|
|
8
|
-
import { IpcClientEventSender } from '@/types/ipcClientEvent';
|
|
4
|
+
import { AppBrowsersIdentifiers, WindowTemplateIdentifiers } from '@/appBrowsers';
|
|
5
|
+
import { getIpcContext } from '@/utils/ipc';
|
|
9
6
|
|
|
10
|
-
import { ControllerModule,
|
|
7
|
+
import { ControllerModule, IpcMethod, shortcut } from './index';
|
|
11
8
|
|
|
12
9
|
export default class BrowserWindowsCtr extends ControllerModule {
|
|
10
|
+
static override readonly groupName = 'windows';
|
|
11
|
+
|
|
13
12
|
@shortcut('showApp')
|
|
14
13
|
async toggleMainWindow() {
|
|
15
14
|
const mainWindow = this.app.browserManager.getMainWindow();
|
|
16
15
|
mainWindow.toggleVisible();
|
|
17
16
|
}
|
|
18
17
|
|
|
19
|
-
@
|
|
18
|
+
@IpcMethod()
|
|
20
19
|
async openSettingsWindow(options?: string | OpenSettingsWindowOptions) {
|
|
21
20
|
const normalizedOptions: OpenSettingsWindowOptions =
|
|
22
21
|
typeof options === 'string' || options === undefined
|
|
@@ -53,26 +52,32 @@ export default class BrowserWindowsCtr extends ControllerModule {
|
|
|
53
52
|
}
|
|
54
53
|
}
|
|
55
54
|
|
|
56
|
-
@
|
|
57
|
-
closeWindow(
|
|
58
|
-
this.
|
|
55
|
+
@IpcMethod()
|
|
56
|
+
closeWindow() {
|
|
57
|
+
this.withSenderIdentifier((identifier) => {
|
|
58
|
+
this.app.browserManager.closeWindow(identifier);
|
|
59
|
+
});
|
|
59
60
|
}
|
|
60
61
|
|
|
61
|
-
@
|
|
62
|
-
minimizeWindow(
|
|
63
|
-
this.
|
|
62
|
+
@IpcMethod()
|
|
63
|
+
minimizeWindow() {
|
|
64
|
+
this.withSenderIdentifier((identifier) => {
|
|
65
|
+
this.app.browserManager.minimizeWindow(identifier);
|
|
66
|
+
});
|
|
64
67
|
}
|
|
65
68
|
|
|
66
|
-
@
|
|
67
|
-
maximizeWindow(
|
|
68
|
-
this.
|
|
69
|
+
@IpcMethod()
|
|
70
|
+
maximizeWindow() {
|
|
71
|
+
this.withSenderIdentifier((identifier) => {
|
|
72
|
+
this.app.browserManager.maximizeWindow(identifier);
|
|
73
|
+
});
|
|
69
74
|
}
|
|
70
75
|
|
|
71
76
|
/**
|
|
72
77
|
* Handle route interception requests
|
|
73
78
|
* Responsible for handling route interception requests from the renderer process
|
|
74
79
|
*/
|
|
75
|
-
@
|
|
80
|
+
@IpcMethod()
|
|
76
81
|
async interceptRoute(params: InterceptRouteParams) {
|
|
77
82
|
const { path, source } = params;
|
|
78
83
|
console.log(
|
|
@@ -115,7 +120,7 @@ export default class BrowserWindowsCtr extends ControllerModule {
|
|
|
115
120
|
/**
|
|
116
121
|
* Create a new multi-instance window
|
|
117
122
|
*/
|
|
118
|
-
@
|
|
123
|
+
@IpcMethod()
|
|
119
124
|
async createMultiInstanceWindow(params: {
|
|
120
125
|
path: string;
|
|
121
126
|
templateId: WindowTemplateIdentifiers;
|
|
@@ -149,7 +154,7 @@ export default class BrowserWindowsCtr extends ControllerModule {
|
|
|
149
154
|
/**
|
|
150
155
|
* Get all windows by template
|
|
151
156
|
*/
|
|
152
|
-
@
|
|
157
|
+
@IpcMethod()
|
|
153
158
|
async getWindowsByTemplate(templateId: string) {
|
|
154
159
|
try {
|
|
155
160
|
const windowIds = this.app.browserManager.getWindowsByTemplate(templateId);
|
|
@@ -169,7 +174,7 @@ export default class BrowserWindowsCtr extends ControllerModule {
|
|
|
169
174
|
/**
|
|
170
175
|
* Close all windows by template
|
|
171
176
|
*/
|
|
172
|
-
@
|
|
177
|
+
@IpcMethod()
|
|
173
178
|
async closeWindowsByTemplate(templateId: string) {
|
|
174
179
|
try {
|
|
175
180
|
this.app.browserManager.closeWindowsByTemplate(templateId);
|
|
@@ -191,4 +196,12 @@ export default class BrowserWindowsCtr extends ControllerModule {
|
|
|
191
196
|
const browser = this.app.browserManager.retrieveByIdentifier(targetWindow);
|
|
192
197
|
browser.show();
|
|
193
198
|
}
|
|
199
|
+
|
|
200
|
+
private withSenderIdentifier(fn: (identifier: string) => void) {
|
|
201
|
+
const context = getIpcContext();
|
|
202
|
+
if (!context) return;
|
|
203
|
+
const identifier = this.app.browserManager.getIdentifierByWebContents(context.sender);
|
|
204
|
+
if (!identifier) return;
|
|
205
|
+
fn(identifier);
|
|
206
|
+
}
|
|
194
207
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { ControllerModule,
|
|
1
|
+
import { ControllerModule, IpcMethod } from './index';
|
|
2
2
|
|
|
3
3
|
export default class DevtoolsCtr extends ControllerModule {
|
|
4
|
-
|
|
4
|
+
static override readonly groupName = 'devtools';
|
|
5
|
+
|
|
6
|
+
@IpcMethod()
|
|
5
7
|
async openDevtools() {
|
|
6
8
|
const devtoolsBrowser = this.app.browserManager.retrieveByIdentifier('devtools');
|
|
7
9
|
devtoolsBrowser.show();
|
|
@@ -30,19 +30,20 @@ import { FileResult, SearchOptions } from '@/types/fileSearch';
|
|
|
30
30
|
import { makeSureDirExist } from '@/utils/file-system';
|
|
31
31
|
import { createLogger } from '@/utils/logger';
|
|
32
32
|
|
|
33
|
-
import { ControllerModule,
|
|
33
|
+
import { ControllerModule, IpcMethod } from './index';
|
|
34
34
|
|
|
35
35
|
// Create logger
|
|
36
36
|
const logger = createLogger('controllers:LocalFileCtr');
|
|
37
37
|
|
|
38
38
|
export default class LocalFileCtr extends ControllerModule {
|
|
39
|
+
static override readonly groupName = 'localSystem';
|
|
39
40
|
private get searchService() {
|
|
40
41
|
return this.app.getService(FileSearchService);
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
// ==================== File Operation ====================
|
|
44
45
|
|
|
45
|
-
@
|
|
46
|
+
@IpcMethod()
|
|
46
47
|
async handleOpenLocalFile({ path: filePath }: OpenLocalFileParams): Promise<{
|
|
47
48
|
error?: string;
|
|
48
49
|
success: boolean;
|
|
@@ -59,7 +60,7 @@ export default class LocalFileCtr extends ControllerModule {
|
|
|
59
60
|
}
|
|
60
61
|
}
|
|
61
62
|
|
|
62
|
-
@
|
|
63
|
+
@IpcMethod()
|
|
63
64
|
async handleOpenLocalFolder({ path: targetPath, isDirectory }: OpenLocalFolderParams): Promise<{
|
|
64
65
|
error?: string;
|
|
65
66
|
success: boolean;
|
|
@@ -77,7 +78,7 @@ export default class LocalFileCtr extends ControllerModule {
|
|
|
77
78
|
}
|
|
78
79
|
}
|
|
79
80
|
|
|
80
|
-
@
|
|
81
|
+
@IpcMethod()
|
|
81
82
|
async readFiles({ paths }: LocalReadFilesParams): Promise<LocalReadFileResult[]> {
|
|
82
83
|
logger.debug('Starting batch file reading:', { count: paths.length });
|
|
83
84
|
|
|
@@ -94,7 +95,7 @@ export default class LocalFileCtr extends ControllerModule {
|
|
|
94
95
|
return results;
|
|
95
96
|
}
|
|
96
97
|
|
|
97
|
-
@
|
|
98
|
+
@IpcMethod()
|
|
98
99
|
async readFile({
|
|
99
100
|
path: filePath,
|
|
100
101
|
loc,
|
|
@@ -192,7 +193,7 @@ export default class LocalFileCtr extends ControllerModule {
|
|
|
192
193
|
}
|
|
193
194
|
}
|
|
194
195
|
|
|
195
|
-
@
|
|
196
|
+
@IpcMethod()
|
|
196
197
|
async listLocalFiles({ path: dirPath }: ListLocalFileParams): Promise<FileResult[]> {
|
|
197
198
|
logger.debug('Listing directory contents:', { dirPath });
|
|
198
199
|
|
|
@@ -250,7 +251,7 @@ export default class LocalFileCtr extends ControllerModule {
|
|
|
250
251
|
}
|
|
251
252
|
}
|
|
252
253
|
|
|
253
|
-
@
|
|
254
|
+
@IpcMethod()
|
|
254
255
|
async handleMoveFiles({ items }: MoveLocalFilesParams): Promise<LocalMoveFilesResultItem[]> {
|
|
255
256
|
logger.debug('Starting batch file move:', { itemsCount: items?.length });
|
|
256
257
|
|
|
@@ -355,7 +356,7 @@ export default class LocalFileCtr extends ControllerModule {
|
|
|
355
356
|
return results;
|
|
356
357
|
}
|
|
357
358
|
|
|
358
|
-
@
|
|
359
|
+
@IpcMethod()
|
|
359
360
|
async handleRenameFile({
|
|
360
361
|
path: currentPath,
|
|
361
362
|
newName,
|
|
@@ -440,7 +441,7 @@ export default class LocalFileCtr extends ControllerModule {
|
|
|
440
441
|
}
|
|
441
442
|
}
|
|
442
443
|
|
|
443
|
-
@
|
|
444
|
+
@IpcMethod()
|
|
444
445
|
async handleWriteFile({ path: filePath, content }: WriteLocalFileParams) {
|
|
445
446
|
const logPrefix = `[Writing file ${filePath}]`;
|
|
446
447
|
logger.debug(`${logPrefix} Starting to write file`, { contentLength: content?.length });
|
|
@@ -485,7 +486,7 @@ export default class LocalFileCtr extends ControllerModule {
|
|
|
485
486
|
/**
|
|
486
487
|
* Handle IPC event for local file search
|
|
487
488
|
*/
|
|
488
|
-
@
|
|
489
|
+
@IpcMethod()
|
|
489
490
|
async handleLocalFilesSearch(params: LocalSearchFilesParams): Promise<FileResult[]> {
|
|
490
491
|
logger.debug('Received file search request:', {
|
|
491
492
|
directory: params.directory,
|
|
@@ -523,7 +524,7 @@ export default class LocalFileCtr extends ControllerModule {
|
|
|
523
524
|
}
|
|
524
525
|
}
|
|
525
526
|
|
|
526
|
-
@
|
|
527
|
+
@IpcMethod()
|
|
527
528
|
async handleGrepContent(params: GrepContentParams): Promise<GrepContentResult> {
|
|
528
529
|
const {
|
|
529
530
|
pattern,
|
|
@@ -639,7 +640,7 @@ export default class LocalFileCtr extends ControllerModule {
|
|
|
639
640
|
}
|
|
640
641
|
}
|
|
641
642
|
|
|
642
|
-
@
|
|
643
|
+
@IpcMethod()
|
|
643
644
|
async handleGlobFiles({
|
|
644
645
|
path: searchPath = process.cwd(),
|
|
645
646
|
pattern,
|
|
@@ -680,7 +681,7 @@ export default class LocalFileCtr extends ControllerModule {
|
|
|
680
681
|
|
|
681
682
|
// ==================== File Editing ====================
|
|
682
683
|
|
|
683
|
-
@
|
|
684
|
+
@IpcMethod()
|
|
684
685
|
async handleEditFile({
|
|
685
686
|
file_path: filePath,
|
|
686
687
|
new_string,
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { ControllerModule,
|
|
1
|
+
import { ControllerModule, IpcMethod } from './index';
|
|
2
2
|
|
|
3
3
|
export default class MenuController extends ControllerModule {
|
|
4
|
+
static override readonly groupName = 'menu';
|
|
4
5
|
/**
|
|
5
6
|
* Refresh menu
|
|
6
7
|
*/
|
|
7
|
-
@
|
|
8
|
+
@IpcMethod()
|
|
8
9
|
refreshAppMenu() {
|
|
9
10
|
// Note: May need to decide whether to allow renderer process to refresh all menus based on specific circumstances
|
|
10
11
|
return this.app.menuManager.refreshMenus();
|
|
@@ -13,7 +14,7 @@ export default class MenuController extends ControllerModule {
|
|
|
13
14
|
/**
|
|
14
15
|
* Show context menu
|
|
15
16
|
*/
|
|
16
|
-
@
|
|
17
|
+
@IpcMethod()
|
|
17
18
|
showContextMenu(params: { data?: any; type: string }) {
|
|
18
19
|
return this.app.menuManager.showContextMenu(params.type, params.data);
|
|
19
20
|
}
|
|
@@ -21,7 +22,7 @@ export default class MenuController extends ControllerModule {
|
|
|
21
22
|
/**
|
|
22
23
|
* Set development menu visibility
|
|
23
24
|
*/
|
|
24
|
-
@
|
|
25
|
+
@IpcMethod()
|
|
25
26
|
setDevMenuVisibility(visible: boolean) {
|
|
26
27
|
// Call MenuManager method to rebuild application menu
|
|
27
28
|
return this.app.menuManager.rebuildAppMenu({ showDevItems: visible });
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
ProxyDispatcherManager,
|
|
12
12
|
ProxyTestResult,
|
|
13
13
|
} from '../modules/networkProxy';
|
|
14
|
-
import { ControllerModule,
|
|
14
|
+
import { ControllerModule, IpcMethod } from './index';
|
|
15
15
|
|
|
16
16
|
// Create logger
|
|
17
17
|
const logger = createLogger('controllers:NetworkProxyCtr');
|
|
@@ -21,10 +21,11 @@ const logger = createLogger('controllers:NetworkProxyCtr');
|
|
|
21
21
|
* 处理桌面应用的网络代理相关功能
|
|
22
22
|
*/
|
|
23
23
|
export default class NetworkProxyCtr extends ControllerModule {
|
|
24
|
+
static override readonly groupName = 'networkProxy';
|
|
24
25
|
/**
|
|
25
26
|
* 获取代理设置
|
|
26
27
|
*/
|
|
27
|
-
@
|
|
28
|
+
@IpcMethod()
|
|
28
29
|
async getDesktopSettings(): Promise<NetworkProxySettings> {
|
|
29
30
|
try {
|
|
30
31
|
const settings = this.app.storeManager.get(
|
|
@@ -45,32 +46,30 @@ export default class NetworkProxyCtr extends ControllerModule {
|
|
|
45
46
|
/**
|
|
46
47
|
* 设置代理配置
|
|
47
48
|
*/
|
|
48
|
-
@
|
|
49
|
-
async setProxySettings(config: NetworkProxySettings): Promise<void> {
|
|
49
|
+
@IpcMethod()
|
|
50
|
+
async setProxySettings(config: Partial<NetworkProxySettings>): Promise<void> {
|
|
50
51
|
try {
|
|
51
|
-
// 验证配置
|
|
52
|
-
const validation = ProxyConfigValidator.validate(config);
|
|
53
|
-
if (!validation.isValid) {
|
|
54
|
-
const errorMessage = `Invalid proxy configuration: ${validation.errors.join(', ')}`;
|
|
55
|
-
logger.error(errorMessage);
|
|
56
|
-
throw new Error(errorMessage);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
52
|
// 获取当前配置
|
|
60
53
|
const currentConfig = this.app.storeManager.get(
|
|
61
54
|
'networkProxy',
|
|
62
55
|
defaultProxySettings,
|
|
63
56
|
) as NetworkProxySettings;
|
|
64
57
|
|
|
65
|
-
//
|
|
66
|
-
|
|
58
|
+
// 合并配置并验证
|
|
59
|
+
const newConfig = merge({}, currentConfig, config);
|
|
60
|
+
|
|
61
|
+
const validation = ProxyConfigValidator.validate(newConfig);
|
|
62
|
+
if (!validation.isValid) {
|
|
63
|
+
const errorMessage = `Invalid proxy configuration: ${validation.errors.join(', ')}`;
|
|
64
|
+
logger.error(errorMessage);
|
|
65
|
+
throw new Error(errorMessage);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (isEqual(currentConfig, newConfig)) {
|
|
67
69
|
logger.debug('Proxy settings unchanged, skipping update');
|
|
68
70
|
return;
|
|
69
71
|
}
|
|
70
72
|
|
|
71
|
-
// 合并配置
|
|
72
|
-
const newConfig = merge({}, currentConfig, config);
|
|
73
|
-
|
|
74
73
|
// 应用代理设置
|
|
75
74
|
await ProxyDispatcherManager.applyProxySettings(newConfig);
|
|
76
75
|
|
|
@@ -92,7 +91,7 @@ export default class NetworkProxyCtr extends ControllerModule {
|
|
|
92
91
|
/**
|
|
93
92
|
* 测试代理连接
|
|
94
93
|
*/
|
|
95
|
-
@
|
|
94
|
+
@IpcMethod()
|
|
96
95
|
async testProxyConnection(url: string): Promise<{ message?: string; success: boolean }> {
|
|
97
96
|
try {
|
|
98
97
|
const result = await ProxyConnectionTester.testConnection(url);
|
|
@@ -112,7 +111,7 @@ export default class NetworkProxyCtr extends ControllerModule {
|
|
|
112
111
|
/**
|
|
113
112
|
* 测试指定代理配置
|
|
114
113
|
*/
|
|
115
|
-
@
|
|
114
|
+
@IpcMethod()
|
|
116
115
|
async testProxyConfig({
|
|
117
116
|
config,
|
|
118
117
|
testUrl,
|
|
@@ -7,11 +7,12 @@ import { macOS, windows } from 'electron-is';
|
|
|
7
7
|
|
|
8
8
|
import { createLogger } from '@/utils/logger';
|
|
9
9
|
|
|
10
|
-
import { ControllerModule,
|
|
10
|
+
import { ControllerModule, IpcMethod } from './index';
|
|
11
11
|
|
|
12
12
|
const logger = createLogger('controllers:NotificationCtr');
|
|
13
13
|
|
|
14
14
|
export default class NotificationCtr extends ControllerModule {
|
|
15
|
+
static override readonly groupName = 'notification';
|
|
15
16
|
/**
|
|
16
17
|
* Set up desktop notifications after the application is ready
|
|
17
18
|
*/
|
|
@@ -51,7 +52,7 @@ export default class NotificationCtr extends ControllerModule {
|
|
|
51
52
|
/**
|
|
52
53
|
* Show system desktop notification (only when window is hidden)
|
|
53
54
|
*/
|
|
54
|
-
@
|
|
55
|
+
@IpcMethod()
|
|
55
56
|
async showDesktopNotification(
|
|
56
57
|
params: ShowDesktopNotificationParams,
|
|
57
58
|
): Promise<DesktopNotificationResult> {
|
|
@@ -126,7 +127,7 @@ export default class NotificationCtr extends ControllerModule {
|
|
|
126
127
|
/**
|
|
127
128
|
* Check if the main window is hidden
|
|
128
129
|
*/
|
|
129
|
-
@
|
|
130
|
+
@IpcMethod()
|
|
130
131
|
isMainWindowHidden(): boolean {
|
|
131
132
|
try {
|
|
132
133
|
const mainWindow = this.app.browserManager.getMainWindow();
|
|
@@ -7,7 +7,7 @@ import { URL } from 'node:url';
|
|
|
7
7
|
import { OFFICIAL_CLOUD_SERVER } from '@/const/env';
|
|
8
8
|
import { createLogger } from '@/utils/logger';
|
|
9
9
|
|
|
10
|
-
import { ControllerModule,
|
|
10
|
+
import { ControllerModule, IpcMethod } from './index';
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Non-retryable OIDC error codes
|
|
@@ -39,6 +39,7 @@ const logger = createLogger('controllers:RemoteServerConfigCtr');
|
|
|
39
39
|
* Used to manage custom remote LobeChat server configuration
|
|
40
40
|
*/
|
|
41
41
|
export default class RemoteServerConfigCtr extends ControllerModule {
|
|
42
|
+
static override readonly groupName = 'remoteServer';
|
|
42
43
|
/**
|
|
43
44
|
* Key used to store encrypted tokens in electron-store.
|
|
44
45
|
*/
|
|
@@ -47,7 +48,7 @@ export default class RemoteServerConfigCtr extends ControllerModule {
|
|
|
47
48
|
/**
|
|
48
49
|
* Get remote server configuration
|
|
49
50
|
*/
|
|
50
|
-
@
|
|
51
|
+
@IpcMethod()
|
|
51
52
|
async getRemoteServerConfig() {
|
|
52
53
|
logger.debug('Getting remote server configuration');
|
|
53
54
|
const { storeManager } = this.app;
|
|
@@ -64,7 +65,7 @@ export default class RemoteServerConfigCtr extends ControllerModule {
|
|
|
64
65
|
/**
|
|
65
66
|
* Set remote server configuration
|
|
66
67
|
*/
|
|
67
|
-
@
|
|
68
|
+
@IpcMethod()
|
|
68
69
|
async setRemoteServerConfig(config: Partial<DataSyncConfig>) {
|
|
69
70
|
logger.info(
|
|
70
71
|
`Setting remote server storageMode: active=${config.active}, storageMode=${config.storageMode}, url=${config.remoteServerUrl}`,
|
|
@@ -81,7 +82,7 @@ export default class RemoteServerConfigCtr extends ControllerModule {
|
|
|
81
82
|
/**
|
|
82
83
|
* Clear remote server configuration
|
|
83
84
|
*/
|
|
84
|
-
@
|
|
85
|
+
@IpcMethod()
|
|
85
86
|
async clearRemoteServerConfig() {
|
|
86
87
|
logger.info('Clearing remote server configuration');
|
|
87
88
|
const { storeManager } = this.app;
|
|
@@ -15,7 +15,7 @@ import { defaultProxySettings } from '@/const/store';
|
|
|
15
15
|
import { createLogger } from '@/utils/logger';
|
|
16
16
|
|
|
17
17
|
import RemoteServerConfigCtr from './RemoteServerConfigCtr';
|
|
18
|
-
import { ControllerModule,
|
|
18
|
+
import { ControllerModule, IpcMethod } from './index';
|
|
19
19
|
|
|
20
20
|
// Create logger
|
|
21
21
|
const logger = createLogger('controllers:RemoteServerSyncCtr');
|
|
@@ -25,6 +25,7 @@ const logger = createLogger('controllers:RemoteServerSyncCtr');
|
|
|
25
25
|
* For handling data synchronization with remote servers via IPC.
|
|
26
26
|
*/
|
|
27
27
|
export default class RemoteServerSyncCtr extends ControllerModule {
|
|
28
|
+
static override readonly groupName = 'remoteServerSync';
|
|
28
29
|
/**
|
|
29
30
|
* Cached instance of RemoteServerConfigCtr
|
|
30
31
|
*/
|
|
@@ -345,7 +346,7 @@ export default class RemoteServerSyncCtr extends ControllerModule {
|
|
|
345
346
|
* Handles the 'proxy-trpc-request' IPC call from the renderer process.
|
|
346
347
|
* This method should be invoked by the ipcMain.handle setup in your main process entry point.
|
|
347
348
|
*/
|
|
348
|
-
@
|
|
349
|
+
@IpcMethod()
|
|
349
350
|
public async proxyTRPCRequest(args: ProxyTRPCRequestParams): Promise<ProxyTRPCRequestResult> {
|
|
350
351
|
logger.debug('Received proxyTRPCRequest IPC call:', {
|
|
351
352
|
headers: args.headers,
|
|
@@ -11,7 +11,7 @@ import { randomUUID } from 'node:crypto';
|
|
|
11
11
|
|
|
12
12
|
import { createLogger } from '@/utils/logger';
|
|
13
13
|
|
|
14
|
-
import { ControllerModule,
|
|
14
|
+
import { ControllerModule, IpcMethod } from './index';
|
|
15
15
|
|
|
16
16
|
const logger = createLogger('controllers:ShellCommandCtr');
|
|
17
17
|
|
|
@@ -24,10 +24,11 @@ interface ShellProcess {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
export default class ShellCommandCtr extends ControllerModule {
|
|
27
|
+
static override readonly groupName = 'shellCommand';
|
|
27
28
|
// Shell process management
|
|
28
29
|
private shellProcesses = new Map<string, ShellProcess>();
|
|
29
30
|
|
|
30
|
-
@
|
|
31
|
+
@IpcMethod()
|
|
31
32
|
async handleRunCommand({
|
|
32
33
|
command,
|
|
33
34
|
description,
|
|
@@ -153,7 +154,7 @@ export default class ShellCommandCtr extends ControllerModule {
|
|
|
153
154
|
}
|
|
154
155
|
}
|
|
155
156
|
|
|
156
|
-
@
|
|
157
|
+
@IpcMethod()
|
|
157
158
|
async handleGetCommandOutput({
|
|
158
159
|
filter,
|
|
159
160
|
shell_id,
|
|
@@ -212,7 +213,7 @@ export default class ShellCommandCtr extends ControllerModule {
|
|
|
212
213
|
};
|
|
213
214
|
}
|
|
214
215
|
|
|
215
|
-
@
|
|
216
|
+
@IpcMethod()
|
|
216
217
|
async handleKillCommand({ shell_id }: KillCommandParams): Promise<KillCommandResult> {
|
|
217
218
|
const logPrefix = `[killCommand: ${shell_id}]`;
|
|
218
219
|
logger.debug(`${logPrefix} Attempting to kill shell`);
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { ShortcutUpdateResult } from '@/core/ui/ShortcutManager';
|
|
2
2
|
|
|
3
|
-
import { ControllerModule,
|
|
3
|
+
import { ControllerModule, IpcMethod } from '.';
|
|
4
4
|
|
|
5
5
|
export default class ShortcutController extends ControllerModule {
|
|
6
|
+
static override readonly groupName = 'shortcut';
|
|
6
7
|
/**
|
|
7
8
|
* Get all shortcut configurations
|
|
8
9
|
*/
|
|
9
|
-
@
|
|
10
|
+
@IpcMethod()
|
|
10
11
|
getShortcutsConfig() {
|
|
11
12
|
return this.app.shortcutManager.getShortcutsConfig();
|
|
12
13
|
}
|
|
@@ -14,7 +15,7 @@ export default class ShortcutController extends ControllerModule {
|
|
|
14
15
|
/**
|
|
15
16
|
* Update a single shortcut configuration
|
|
16
17
|
*/
|
|
17
|
-
@
|
|
18
|
+
@IpcMethod()
|
|
18
19
|
updateShortcutConfig({
|
|
19
20
|
id,
|
|
20
21
|
accelerator,
|
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
import { ElectronAppState, ThemeMode } from '@lobechat/electron-client-ipc';
|
|
2
2
|
import { app, nativeTheme, shell, systemPreferences } from 'electron';
|
|
3
3
|
import { macOS } from 'electron-is';
|
|
4
|
-
import { readFileSync, writeFileSync } from 'node:fs';
|
|
5
|
-
import { join } from 'node:path';
|
|
6
4
|
import process from 'node:process';
|
|
7
5
|
|
|
8
|
-
import { DB_SCHEMA_HASH_FILENAME, LOCAL_DATABASE_DIR, userDataDir } from '@/const/dir';
|
|
9
6
|
import { createLogger } from '@/utils/logger';
|
|
10
7
|
|
|
11
|
-
import { ControllerModule,
|
|
8
|
+
import { ControllerModule, IpcMethod } from './index';
|
|
12
9
|
|
|
13
10
|
const logger = createLogger('controllers:SystemCtr');
|
|
14
11
|
|
|
15
12
|
export default class SystemController extends ControllerModule {
|
|
13
|
+
static override readonly groupName = 'system';
|
|
16
14
|
private systemThemeListenerInitialized = false;
|
|
17
15
|
|
|
18
16
|
/**
|
|
@@ -26,7 +24,7 @@ export default class SystemController extends ControllerModule {
|
|
|
26
24
|
* Handles the 'getDesktopAppState' IPC request.
|
|
27
25
|
* Gathers essential application and system information.
|
|
28
26
|
*/
|
|
29
|
-
@
|
|
27
|
+
@IpcMethod()
|
|
30
28
|
async getAppState(): Promise<ElectronAppState> {
|
|
31
29
|
const platform = process.platform;
|
|
32
30
|
const arch = process.arch;
|
|
@@ -56,13 +54,13 @@ export default class SystemController extends ControllerModule {
|
|
|
56
54
|
/**
|
|
57
55
|
* 检查可用性
|
|
58
56
|
*/
|
|
59
|
-
@
|
|
57
|
+
@IpcMethod()
|
|
60
58
|
checkAccessibilityForMacOS() {
|
|
61
59
|
if (!macOS()) return;
|
|
62
60
|
return systemPreferences.isTrustedAccessibilityClient(true);
|
|
63
61
|
}
|
|
64
62
|
|
|
65
|
-
@
|
|
63
|
+
@IpcMethod()
|
|
66
64
|
openExternalLink(url: string) {
|
|
67
65
|
return shell.openExternal(url);
|
|
68
66
|
}
|
|
@@ -70,7 +68,7 @@ export default class SystemController extends ControllerModule {
|
|
|
70
68
|
/**
|
|
71
69
|
* 更新应用语言设置
|
|
72
70
|
*/
|
|
73
|
-
@
|
|
71
|
+
@IpcMethod()
|
|
74
72
|
async updateLocale(locale: string) {
|
|
75
73
|
// 保存语言设置
|
|
76
74
|
this.app.storeManager.set('locale', locale);
|
|
@@ -82,7 +80,7 @@ export default class SystemController extends ControllerModule {
|
|
|
82
80
|
return { success: true };
|
|
83
81
|
}
|
|
84
82
|
|
|
85
|
-
@
|
|
83
|
+
@IpcMethod()
|
|
86
84
|
async updateThemeModeHandler(themeMode: ThemeMode) {
|
|
87
85
|
this.app.storeManager.set('themeMode', themeMode);
|
|
88
86
|
this.app.browserManager.broadcastToAllWindows('themeChanged', { themeMode });
|
|
@@ -91,34 +89,6 @@ export default class SystemController extends ControllerModule {
|
|
|
91
89
|
this.app.browserManager.handleAppThemeChange();
|
|
92
90
|
}
|
|
93
91
|
|
|
94
|
-
@ipcServerEvent('getDatabasePath')
|
|
95
|
-
async getDatabasePath() {
|
|
96
|
-
return join(this.app.appStoragePath, LOCAL_DATABASE_DIR);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
@ipcServerEvent('getDatabaseSchemaHash')
|
|
100
|
-
async getDatabaseSchemaHash() {
|
|
101
|
-
try {
|
|
102
|
-
return readFileSync(this.DB_SCHEMA_HASH_PATH, 'utf8');
|
|
103
|
-
} catch {
|
|
104
|
-
return undefined;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
@ipcServerEvent('getUserDataPath')
|
|
109
|
-
async getUserDataPath() {
|
|
110
|
-
return userDataDir;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
@ipcServerEvent('setDatabaseSchemaHash')
|
|
114
|
-
async setDatabaseSchemaHash(hash: string) {
|
|
115
|
-
writeFileSync(this.DB_SCHEMA_HASH_PATH, hash, 'utf8');
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
private get DB_SCHEMA_HASH_PATH() {
|
|
119
|
-
return join(this.app.appStoragePath, DB_SCHEMA_HASH_FILENAME);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
92
|
/**
|
|
123
93
|
* Initialize system theme listener to monitor OS theme changes
|
|
124
94
|
*/
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
|
|
4
|
+
import { DB_SCHEMA_HASH_FILENAME, LOCAL_DATABASE_DIR, userDataDir } from '@/const/dir';
|
|
5
|
+
|
|
6
|
+
import { ControllerModule, IpcServerMethod } from './index';
|
|
7
|
+
|
|
8
|
+
export default class SystemServerCtr extends ControllerModule {
|
|
9
|
+
static override readonly groupName = 'system';
|
|
10
|
+
|
|
11
|
+
@IpcServerMethod()
|
|
12
|
+
async getDatabasePath() {
|
|
13
|
+
return join(this.app.appStoragePath, LOCAL_DATABASE_DIR);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
@IpcServerMethod()
|
|
17
|
+
async getDatabaseSchemaHash() {
|
|
18
|
+
try {
|
|
19
|
+
return readFileSync(this.DB_SCHEMA_HASH_PATH, 'utf8');
|
|
20
|
+
} catch {
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@IpcServerMethod()
|
|
26
|
+
async getUserDataPath() {
|
|
27
|
+
return userDataDir;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
@IpcServerMethod()
|
|
31
|
+
async setDatabaseSchemaHash(hash: string) {
|
|
32
|
+
writeFileSync(this.DB_SCHEMA_HASH_PATH, hash, 'utf8');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
private get DB_SCHEMA_HASH_PATH() {
|
|
36
|
+
return join(this.app.appStoragePath, DB_SCHEMA_HASH_FILENAME);
|
|
37
|
+
}
|
|
38
|
+
}
|