优化: df-miniapp 跨端 AI Chat 更新(会话前基线收尾)

- ws.ts 心跳 pong 闭环 + useAiChat 看门狗治半连接挂死

- pages 新增 settings/ + chat/conversations 更新 + types events/relay + mdRenderer + tsconfig
This commit is contained in:
lxy
2026-08-05 22:14:38 +08:00
parent a91e950874
commit 71fdaac1b4
10 changed files with 1361 additions and 192 deletions
+18 -4
View File
@@ -33,6 +33,9 @@
import { getConfig } from '@/config'
import type { BroadcastMessage, Hello, MiniCommand, ControlMessage } from '@/types/relay'
/** 调试日志门控(P1 走查:生产 console.log 过微信 bridge,热路径成本)。dev=true / build=false。 */
const DEBUG = import.meta.env.DEV
/** WS 连接状态 */
export type WsStatus = 'disconnected' | 'connecting' | 'connected' | 'handshaking' | 'reconnecting'
@@ -86,6 +89,8 @@ class WsClient {
private reconnectAttempts = 0
/** 主动关闭标志(用户调用 disconnect 时置 true,不再触发重连) */
private manualClose = false
/** 可恢复标志:达上限 disconnected 时置 true,允许 connect/resumeIfDisconnected 重置重连 */
private recoverable = false
/**
* 握手完成前积压的命令队列(send 在 !handshaked 时不丢弃,入队等 hello_ack 后补发)。
* 治「握手成功到首帧竞态丢命令」:握手刚翻 true 时 relay 设备路由表可能未就绪,
@@ -112,7 +117,8 @@ class WsClient {
return
}
this.manualClose = false
// 用户主动连接复位重连计数(可与达上限后的自动退避区分,允许手动重试)
this.recoverable = false
// 用户主动连接复位重连计数(可达上限后的 disconnected 也允许手动重试)
this.reconnectAttempts = 0
// 统一经 reconnectNow(幂等 clear timer + cleanup + openSocket),杜绝 reconnecting 态双连
this.reconnectNow()
@@ -138,7 +144,9 @@ class WsClient {
*/
resumeIfDisconnected(): void {
if (this.manualClose) return
if (this.status === 'disconnected' || this.status === 'reconnecting') {
// 已达上限 disconnected(recoverable=true)也允许重置计数并重连
if (this.status === 'disconnected' || this.status === 'reconnecting' || this.recoverable) {
this.recoverable = false
// 用户触发的立即重连(onShow 抢占退避)复位计数,允许达上限后手动恢复
this.reconnectAttempts = 0
this.reconnectNow()
@@ -174,7 +182,7 @@ class WsClient {
* BroadcastMessage(device_id/kind/source/from 由 relay 填),故客户端仅发业务 JSON。
*/
send(cmd: MiniCommand): boolean {
console.log('[dbg:ws] send', cmd.cmd, 'socket=', !!this.socket, 'handshaked=', this.handshaked)
if (DEBUG) console.log('[dbg:ws] send', cmd.cmd, 'socket=', !!this.socket, 'handshaked=', this.handshaked)
if (!this.socket || !this.handshaked) {
// 握手未完成不丢弃,入队待 hello_ack 后补发(治握手成功到首帧竞态丢命令)。
// 仅在未主动断开(manualClose=false)且连接尚有恢复预期时入队,
@@ -508,8 +516,14 @@ class WsClient {
// 用户手动重连(connect/resumeIfDisconnected)复位计数后可重新开始。
if (this.reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {
console.warn(`[WsClient] 已达最大重连次数 ${MAX_RECONNECT_ATTEMPTS},停止重连`)
// 不清 cleanup(保留 manualClose 不变),仅设状态 + 停退避 timer
// 让 connect()/resumeIfDisconnected() 可重置计数后恢复
this.setStatus('disconnected', '已达最大重连次数,请检查中继地址/网络后手动重连')
this.cleanup()
this.recoverable = true
if (this.reconnectTimer) {
clearTimeout(this.reconnectTimer)
this.reconnectTimer = null
}
return
}
const cfg = getConfig()