Skip to content

Commit 7ae9b4a

Browse files
committed
fix: 修复代码审查发现的潜在 bug
- wsClient: WebSocket onerror 返回 Error 对象而非原始 Event - digitalHumanStore: setExpressionIntensity 处理 NaN 输入 - chatTransport: emotion 类型添加运行时白名单验证 - useTheme/i18n: localStorage 操作添加 try-catch 保护
1 parent 9fe5da6 commit 7ae9b4a

5 files changed

Lines changed: 42 additions & 12 deletions

File tree

src/core/dialogue/chatTransport.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,14 @@ export interface ChatTransportCapabilities {
4040

4141
const DEFAULT_TIMEOUT_MS = 15000;
4242

43+
const VALID_EMOTIONS = ['neutral', 'happy', 'surprised', 'sad', 'angry'] as const;
44+
45+
const validateEmotion = (emotion: string): ChatResponsePayload['emotion'] => {
46+
return VALID_EMOTIONS.includes(emotion as (typeof VALID_EMOTIONS)[number])
47+
? (emotion as ChatResponsePayload['emotion'])
48+
: 'neutral';
49+
};
50+
4351
const buildEmptyResponse = (): ChatResponsePayload => ({
4452
replyText: '',
4553
emotion: 'neutral',
@@ -132,7 +140,7 @@ async function* streamOverWebSocket(
132140
if (event.type === 'done') {
133141
callbacks.onDone?.({
134142
replyText: event.replyText,
135-
emotion: event.emotion as ChatResponsePayload['emotion'],
143+
emotion: validateEmotion(event.emotion),
136144
action: event.action,
137145
});
138146
setTerminalEvent(event);
@@ -187,7 +195,7 @@ async function* streamOverWebSocket(
187195
return {
188196
response: {
189197
replyText: terminal.replyText,
190-
emotion: terminal.emotion as ChatResponsePayload['emotion'],
198+
emotion: validateEmotion(terminal.emotion),
191199
action: terminal.action,
192200
},
193201
connectionStatus: 'connected' as const,

src/core/dialogue/wsClient.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,9 @@ export class MetaHumanWSClient {
105105
}
106106
};
107107

108-
this.ws.onerror = (event) => {
109-
108+
this.ws.onerror = () => {
110109
this.rejectConnect = null;
111-
reject(event);
110+
reject(new Error('WebSocket 连接失败'));
112111
};
113112

114113
this.ws.onclose = () => {
@@ -136,7 +135,6 @@ export class MetaHumanWSClient {
136135
if (this.rejectConnect) {
137136
this.rejectConnect(new Error('WebSocket disconnected'));
138137
this.rejectConnect = null;
139-
140138
}
141139
this.ws?.close();
142140
this.ws = null;

src/hooks/useTheme.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,34 @@ function resolveTheme(theme: Theme): ResolvedTheme {
1212
return theme === 'system' ? getSystemTheme() : theme;
1313
}
1414

15+
function getStoredTheme(): Theme {
16+
try {
17+
return (localStorage.getItem('theme') as Theme) || 'system';
18+
} catch {
19+
return 'system';
20+
}
21+
}
22+
23+
function setStoredTheme(theme: Theme): void {
24+
try {
25+
localStorage.setItem('theme', theme);
26+
} catch {
27+
// Ignore storage write failures
28+
}
29+
}
30+
1531
export function useTheme() {
1632
const [theme, setThemeState] = useState<Theme>(() => {
1733
if (typeof window === 'undefined') return 'system';
18-
return (localStorage.getItem('theme') as Theme) || 'system';
34+
return getStoredTheme();
1935
});
2036

2137
const resolved = resolveTheme(theme);
2238

2339
useEffect(() => {
2440
document.documentElement.classList.remove('light', 'dark');
2541
document.documentElement.classList.add(resolved);
26-
localStorage.setItem('theme', theme);
42+
setStoredTheme(theme);
2743
}, [theme, resolved]);
2844

2945
useEffect(() => {

src/lib/i18n.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -247,8 +247,12 @@ export function getCurrentLanguage(): Language {
247247
if (urlLang === 'zh') return 'zh-CN';
248248

249249
// 2. localStorage(用户偏好)
250-
const stored = localStorage.getItem('preferred-lang') as Language | null;
251-
if (stored === 'en' || stored === 'zh-CN') return stored;
250+
try {
251+
const stored = localStorage.getItem('preferred-lang') as Language | null;
252+
if (stored === 'en' || stored === 'zh-CN') return stored;
253+
} catch {
254+
// Ignore storage read failures
255+
}
252256

253257
// 3. 浏览器语言
254258
const browserLang = navigator.language || '';
@@ -260,7 +264,11 @@ export function getCurrentLanguage(): Language {
260264

261265
// 设置语言
262266
export function setLanguage(lang: Language): void {
263-
localStorage.setItem('preferred-lang', lang);
267+
try {
268+
localStorage.setItem('preferred-lang', lang);
269+
} catch {
270+
// Ignore storage write failures
271+
}
264272
document.documentElement.lang = lang;
265273
document.documentElement.setAttribute('data-lang', lang);
266274

src/store/digitalHumanStore.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ export const useDigitalHumanStore = create<DigitalHumanState>()(
118118
setEmotion: (emotion) => set({ currentEmotion: emotion }),
119119
setExpression: (expression) => set({ currentExpression: expression }),
120120
setExpressionIntensity: (intensity) =>
121-
set({ expressionIntensity: Math.max(0, Math.min(1, intensity)) }),
121+
set({ expressionIntensity: Math.max(0, Math.min(1, intensity || 0)) }),
122122
setBehavior: (behavior) => set({ currentBehavior: behavior }),
123123

124124
// 控制方法

0 commit comments

Comments
 (0)