Skip to content

Commit 71304db

Browse files
committed
fix(perf): 性能模式变更即时生效,活跃采集优雅重启
1 parent acf72e3 commit 71304db

4 files changed

Lines changed: 75 additions & 16 deletions

File tree

‎client/electron/performanceMode.ts‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,16 @@ const CAPTURE_RATE_SCALE: Record<PerformanceMode, number> = {
2727

2828
let currentMode: PerformanceMode = DEFAULT_MODE;
2929

30+
/** 模式变更监听器(供活跃采集循环等消费方热更新,实现即时生效) */
31+
type ModeChangeListener = (mode: PerformanceMode) => void;
32+
const modeListeners = new Set<ModeChangeListener>();
33+
34+
/** 订阅模式变更,返回取消订阅函数 */
35+
export function onPerformanceModeChange(fn: ModeChangeListener): () => void {
36+
modeListeners.add(fn);
37+
return () => { modeListeners.delete(fn); };
38+
}
39+
3040
function configPath(): string {
3141
return join(app.getPath('userData'), 'performance-mode.json');
3242
}
@@ -54,6 +64,10 @@ export function setPerformanceMode(mode: unknown): void {
5464
logger.error('[PerformanceMode] 持久化失败:', err);
5565
}
5666
logger.info(`[PerformanceMode] 模式已设置: ${mode}`);
67+
// 通知消费方(活跃采集循环按新频率重启,使采集策略即时生效而非等下次启动)
68+
modeListeners.forEach((fn) => {
69+
try { fn(mode); } catch (err) { logger.error('[PerformanceMode] 监听回调异常:', err); }
70+
});
5771
}
5872

5973
/** 当前模式 */

‎client/electron/recordingStorage.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
import { app } from 'electron';
1313
import * as path from 'path';
1414
import { mkdir, writeFile, readFile, rm } from 'fs/promises';
15-
import { safeHandle } from '../ipcUtils.js';
16-
import { logger } from '../logger.js';
15+
import { safeHandle } from './ipcUtils.js';
16+
import { logger } from './logger.js';
1717

1818
/** 安全文件名:字母数字/下划线/连字符,1-80 字符(防路径穿越) */
1919
const SAFE_NAME_RE = /^[A-Za-z0-9_-]{1,80}$/;

‎client/electron/screenCaptureHandlers.ts‎

Lines changed: 56 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import type { ScreenCaptureOptions, ScreenshotFrameData } from './screenCapture.
1414
import { safeHandle, getMainWindowId } from './ipcUtils.js';
1515
import { logger } from './logger.js';
1616
import { scoreAndFilterWindows } from './windowScorer.js';
17-
import { getCaptureRateScale } from './performanceMode.js';
17+
import { getCaptureRateScale, onPerformanceModeChange } from './performanceMode.js';
1818

1919
// ================================================================
2020
// 模块级状态
@@ -23,6 +23,15 @@ import { getCaptureRateScale } from './performanceMode.js';
2323
/** 当前活跃的截图采集实例 */
2424
let activeCapture: ScreenCapture | null = null;
2525

26+
/** 活跃采集的原始参数(未缩放 interval),供性能模式变更后按新频率重建实例 */
27+
let activeOptions: ScreenCaptureOptions | null = null;
28+
29+
/** 活跃采集的帧推送目标窗口(重启实例后保持推送不中断) */
30+
let activeSenderWin: BrowserWindow | null = null;
31+
32+
/** 性能模式变更订阅的取消函数 */
33+
let unsubscribeModeChange: (() => void) | null = null;
34+
2635
/** screen_capture_start 防抖:500ms 内多次调用只响应最后一次 */
2736
let startDebounceTimer: ReturnType<typeof setTimeout> | null = null;
2837
const START_DEBOUNCE_MS = 500;
@@ -45,10 +54,43 @@ let lastWindowIds: Set<string> = new Set();
4554

4655
const WINDOW_WATCH_INTERVAL_MS = 3000;
4756

57+
/** 按性能模式缩放采集间隔(静谧档 scale=0.5 → 间隔翻倍、频率减半,降低开销) */
58+
function applyRateScale(options: ScreenCaptureOptions): ScreenCaptureOptions {
59+
const scaled = { ...options };
60+
const rateScale = getCaptureRateScale();
61+
if (typeof scaled.interval === 'number' && rateScale !== 1) {
62+
scaled.interval = Math.min(60000, Math.round(scaled.interval / rateScale));
63+
}
64+
return scaled;
65+
}
66+
67+
/** 销毁旧实例并按其参数/推送目标重建采集(start 与性能模式重启共用) */
68+
function startCaptureWith(senderWin: BrowserWindow | null, options: ScreenCaptureOptions): void {
69+
if (activeCapture) {
70+
activeCapture.dispose();
71+
activeCapture = null;
72+
}
73+
activeCapture = new ScreenCapture(applyRateScale(options), (frame: ScreenshotFrameData) => {
74+
if (senderWin && !senderWin.isDestroyed()) {
75+
senderWin.webContents.send('screen_capture_frame', frame);
76+
}
77+
});
78+
activeCapture.start();
79+
}
80+
4881
/**
4982
* 注册屏幕截图与窗口监听相关的 IPC handler
5083
*/
5184
export function registerScreenCaptureHandlers(): void {
85+
// 性能模式变更 → 活跃采集按新频率优雅重启(即时生效,替代"等下次启动")
86+
unsubscribeModeChange = onPerformanceModeChange(() => {
87+
if (!activeCapture || !activeOptions) return;
88+
const senderWin = activeSenderWin;
89+
const options = activeOptions;
90+
logger.info('[IPC] 性能模式变更,采集按新频率重启');
91+
startCaptureWith(senderWin, options);
92+
});
93+
5294
safeHandle(
5395
'screen_capture_start',
5496
async (event, options: ScreenCaptureOptions) => {
@@ -93,19 +135,11 @@ export function registerScreenCaptureHandlers(): void {
93135
safeOptions.interval = 5000;
94136
}
95137

96-
// 按性能模式缩放采集间隔(静谧档 scale=0.5 → 间隔翻倍、频率减半,降低开销)
97-
const rateScale = getCaptureRateScale();
98-
if (typeof safeOptions.interval === 'number' && rateScale !== 1) {
99-
safeOptions.interval = Math.min(60000, Math.round(safeOptions.interval / rateScale));
100-
}
138+
// 记录原始参数与推送目标(供性能模式变更时重启采集)
139+
activeOptions = safeOptions;
140+
activeSenderWin = senderWin;
101141

102-
activeCapture = new ScreenCapture(safeOptions, (frame: ScreenshotFrameData) => {
103-
if (senderWin && !senderWin.isDestroyed()) {
104-
senderWin.webContents.send('screen_capture_frame', frame);
105-
}
106-
});
107-
108-
activeCapture.start();
142+
startCaptureWith(senderWin, safeOptions);
109143
logger.info('[IPC] screen_capture_start 已启动(防抖后)');
110144
resolve({ success: true });
111145
}, START_DEBOUNCE_MS);
@@ -136,6 +170,8 @@ export function registerScreenCaptureHandlers(): void {
136170
activeCapture = null;
137171
logger.info('[IPC] screen_capture_stop 已停止');
138172
}
173+
activeOptions = null;
174+
activeSenderWin = null;
139175
return { success: true };
140176
});
141177

@@ -226,6 +262,11 @@ export function registerScreenCaptureHandlers(): void {
226262
* 释放屏幕截图相关资源(含防抖定时器与轮询)
227263
*/
228264
export function disposeScreenCaptureHandlers(): void {
265+
// 注销性能模式变更订阅
266+
if (unsubscribeModeChange) {
267+
unsubscribeModeChange();
268+
unsubscribeModeChange = null;
269+
}
229270
// 清理防抖定时器
230271
if (startDebounceTimer) {
231272
clearTimeout(startDebounceTimer);
@@ -245,4 +286,6 @@ export function disposeScreenCaptureHandlers(): void {
245286
activeCapture.dispose();
246287
activeCapture = null;
247288
}
289+
activeOptions = null;
290+
activeSenderWin = null;
248291
}

‎client/src/pages/settings/PerformanceSettings.tsx‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
* 显示名 静谧/从容/澎湃,默认从容(medium)。
77
*
88
* @ai-context: 设置页组件:PerformanceSettings。
9+
* 生效时机:3D 画质/动画即时生效;后台采集频率在变更瞬间优雅重启活跃
10+
* 采集循环即时生效(主进程 onPerformanceModeChange 订阅),不再等下次启动。
911
*/
1012
import { motion } from 'framer-motion';
1113
import { Card } from '@/components/ui';
@@ -136,7 +138,7 @@ export default function PerformanceSettings() {
136138
</div>
137139

138140
<p className="text-c1 text-text-tertiary">
139-
3D 画质与动画即时生效;后台采集频率与进程策略在下次启动后完全生效。
141+
3D 画质与动画即时生效;后台采集频率在变更后立即生效(当前采集循环将按新频率重启)。
140142
</p>
141143
</Card>
142144
);

0 commit comments

Comments
 (0)