fix(electron): add gRPC connection check before subscribing to messages
The app was crashing with "CANCELLED: Cancelled on client" error when opening the app a second time. This happened because: 1. When window was reopened, old gRPC streams were in cancelled state 2. prepareForSign/prepareForKeygen tried to subscribe on cancelled streams 3. The error was unhandled and crashed the app Changes: - Add isConnected() check in prepareForSign() and prepareForKeygen() - Throw meaningful error when gRPC client is not connected - Wrap all prepareFor* calls in try-catch in main.ts - Return user-friendly error message instead of crashing 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
c0229a1139
commit
d051178801
|
|
@ -1174,8 +1174,13 @@ function setupIpcHandlers() {
|
|||
// 这确保在其他方开始发送 TSS 消息时,我们已经准备好接收和缓冲
|
||||
// 即使 keygen 进程还没启动,消息也不会丢失
|
||||
if (tssHandler && 'prepareForKeygen' in tssHandler) {
|
||||
debugLog.info('tss', `Preparing for keygen: subscribing to messages for session ${sessionId}`);
|
||||
(tssHandler as { prepareForKeygen: (sessionId: string, partyId: string) => void }).prepareForKeygen(sessionId, partyId);
|
||||
try {
|
||||
debugLog.info('tss', `Preparing for keygen: subscribing to messages for session ${sessionId}`);
|
||||
(tssHandler as { prepareForKeygen: (sessionId: string, partyId: string) => void }).prepareForKeygen(sessionId, partyId);
|
||||
} catch (prepareErr) {
|
||||
debugLog.error('tss', `Failed to prepare for keygen: ${(prepareErr as Error).message}`);
|
||||
return { success: false, error: `消息订阅失败: ${(prepareErr as Error).message}` };
|
||||
}
|
||||
}
|
||||
|
||||
// 方案 B: 检查 JoinSession 响应中的 session 状态
|
||||
|
|
@ -1287,8 +1292,13 @@ function setupIpcHandlers() {
|
|||
|
||||
// 关键步骤:立即预订阅消息流
|
||||
if (tssHandler && 'prepareForKeygen' in tssHandler) {
|
||||
debugLog.info('tss', `Initiator preparing for keygen: subscribing to messages for session ${result.session_id}`);
|
||||
(tssHandler as { prepareForKeygen: (sessionId: string, partyId: string) => void }).prepareForKeygen(result.session_id, partyId);
|
||||
try {
|
||||
debugLog.info('tss', `Initiator preparing for keygen: subscribing to messages for session ${result.session_id}`);
|
||||
(tssHandler as { prepareForKeygen: (sessionId: string, partyId: string) => void }).prepareForKeygen(result.session_id, partyId);
|
||||
} catch (prepareErr) {
|
||||
debugLog.error('tss', `Failed to prepare for keygen: ${(prepareErr as Error).message}`);
|
||||
return { success: false, error: `消息订阅失败: ${(prepareErr as Error).message}` };
|
||||
}
|
||||
}
|
||||
|
||||
// 方案 B: 检查 JoinSession 响应中的 session 状态
|
||||
|
|
@ -1707,8 +1717,13 @@ function setupIpcHandlers() {
|
|||
|
||||
// 预订阅消息流
|
||||
if (tssHandler && 'prepareForSign' in tssHandler) {
|
||||
debugLog.info('tss', `Initiator preparing for sign: subscribing to messages for session ${result.session_id}`);
|
||||
(tssHandler as TSSHandler).prepareForSign(result.session_id, partyId);
|
||||
try {
|
||||
debugLog.info('tss', `Initiator preparing for sign: subscribing to messages for session ${result.session_id}`);
|
||||
(tssHandler as TSSHandler).prepareForSign(result.session_id, partyId);
|
||||
} catch (prepareErr) {
|
||||
debugLog.error('tss', `Failed to prepare for sign: ${(prepareErr as Error).message}`);
|
||||
return { success: false, error: `消息订阅失败: ${(prepareErr as Error).message}` };
|
||||
}
|
||||
}
|
||||
|
||||
// 检查会话状态
|
||||
|
|
@ -1873,8 +1888,13 @@ function setupIpcHandlers() {
|
|||
|
||||
// 预订阅消息流
|
||||
if (tssHandler && 'prepareForSign' in tssHandler) {
|
||||
debugLog.info('tss', `Preparing for sign: subscribing to messages for session ${params.sessionId}`);
|
||||
(tssHandler as TSSHandler).prepareForSign(params.sessionId, partyId);
|
||||
try {
|
||||
debugLog.info('tss', `Preparing for sign: subscribing to messages for session ${params.sessionId}`);
|
||||
(tssHandler as TSSHandler).prepareForSign(params.sessionId, partyId);
|
||||
} catch (prepareErr) {
|
||||
debugLog.error('tss', `Failed to prepare for sign: ${(prepareErr as Error).message}`);
|
||||
return { success: false, error: `消息订阅失败: ${(prepareErr as Error).message}` };
|
||||
}
|
||||
}
|
||||
|
||||
// 检查会话状态
|
||||
|
|
|
|||
|
|
@ -123,6 +123,12 @@ export class TSSHandler extends EventEmitter {
|
|||
* @param partyId 自己的 party ID
|
||||
*/
|
||||
prepareForKeygen(sessionId: string, partyId: string): void {
|
||||
// 检查 gRPC 连接状态
|
||||
if (!this.grpcClient.isConnected()) {
|
||||
console.error('[TSS] Cannot prepare for keygen: gRPC client not connected');
|
||||
throw new Error('gRPC client not connected');
|
||||
}
|
||||
|
||||
// 如果已经为同一个 session 准备过,跳过
|
||||
if (this.isPrepared && this.sessionId === sessionId) {
|
||||
console.log('[TSS] Already prepared for same session, skip');
|
||||
|
|
@ -489,6 +495,12 @@ export class TSSHandler extends EventEmitter {
|
|||
* @param partyId 自己的 party ID
|
||||
*/
|
||||
prepareForSign(sessionId: string, partyId: string): void {
|
||||
// 检查 gRPC 连接状态
|
||||
if (!this.grpcClient.isConnected()) {
|
||||
console.error('[TSS-SIGN] Cannot prepare for sign: gRPC client not connected');
|
||||
throw new Error('gRPC client not connected');
|
||||
}
|
||||
|
||||
// 如果已经为同一个 session 准备过,跳过
|
||||
if (this.isPrepared && this.sessionId === sessionId) {
|
||||
console.log('[TSS-SIGN] Already prepared for same session, skip');
|
||||
|
|
|
|||
Loading…
Reference in New Issue