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 消息时,我们已经准备好接收和缓冲
|
// 这确保在其他方开始发送 TSS 消息时,我们已经准备好接收和缓冲
|
||||||
// 即使 keygen 进程还没启动,消息也不会丢失
|
// 即使 keygen 进程还没启动,消息也不会丢失
|
||||||
if (tssHandler && 'prepareForKeygen' in tssHandler) {
|
if (tssHandler && 'prepareForKeygen' in tssHandler) {
|
||||||
debugLog.info('tss', `Preparing for keygen: subscribing to messages for session ${sessionId}`);
|
try {
|
||||||
(tssHandler as { prepareForKeygen: (sessionId: string, partyId: string) => void }).prepareForKeygen(sessionId, partyId);
|
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 状态
|
// 方案 B: 检查 JoinSession 响应中的 session 状态
|
||||||
|
|
@ -1287,8 +1292,13 @@ function setupIpcHandlers() {
|
||||||
|
|
||||||
// 关键步骤:立即预订阅消息流
|
// 关键步骤:立即预订阅消息流
|
||||||
if (tssHandler && 'prepareForKeygen' in tssHandler) {
|
if (tssHandler && 'prepareForKeygen' in tssHandler) {
|
||||||
debugLog.info('tss', `Initiator preparing for keygen: subscribing to messages for session ${result.session_id}`);
|
try {
|
||||||
(tssHandler as { prepareForKeygen: (sessionId: string, partyId: string) => void }).prepareForKeygen(result.session_id, partyId);
|
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 状态
|
// 方案 B: 检查 JoinSession 响应中的 session 状态
|
||||||
|
|
@ -1707,8 +1717,13 @@ function setupIpcHandlers() {
|
||||||
|
|
||||||
// 预订阅消息流
|
// 预订阅消息流
|
||||||
if (tssHandler && 'prepareForSign' in tssHandler) {
|
if (tssHandler && 'prepareForSign' in tssHandler) {
|
||||||
debugLog.info('tss', `Initiator preparing for sign: subscribing to messages for session ${result.session_id}`);
|
try {
|
||||||
(tssHandler as TSSHandler).prepareForSign(result.session_id, partyId);
|
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) {
|
if (tssHandler && 'prepareForSign' in tssHandler) {
|
||||||
debugLog.info('tss', `Preparing for sign: subscribing to messages for session ${params.sessionId}`);
|
try {
|
||||||
(tssHandler as TSSHandler).prepareForSign(params.sessionId, partyId);
|
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
|
* @param partyId 自己的 party ID
|
||||||
*/
|
*/
|
||||||
prepareForKeygen(sessionId: string, partyId: string): void {
|
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 准备过,跳过
|
// 如果已经为同一个 session 准备过,跳过
|
||||||
if (this.isPrepared && this.sessionId === sessionId) {
|
if (this.isPrepared && this.sessionId === sessionId) {
|
||||||
console.log('[TSS] Already prepared for same session, skip');
|
console.log('[TSS] Already prepared for same session, skip');
|
||||||
|
|
@ -489,6 +495,12 @@ export class TSSHandler extends EventEmitter {
|
||||||
* @param partyId 自己的 party ID
|
* @param partyId 自己的 party ID
|
||||||
*/
|
*/
|
||||||
prepareForSign(sessionId: string, partyId: string): void {
|
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 准备过,跳过
|
// 如果已经为同一个 session 准备过,跳过
|
||||||
if (this.isPrepared && this.sessionId === sessionId) {
|
if (this.isPrepared && this.sessionId === sessionId) {
|
||||||
console.log('[TSS-SIGN] Already prepared for same session, skip');
|
console.log('[TSS-SIGN] Already prepared for same session, skip');
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue