# ACK 消息类型设计方案

## 概述

ACK（Acknowledgment）消息用于确认接收方已成功接收并处理了发送方的消息。这对于保证消息可靠性和状态同步非常重要。

## ACK 消息类型定义

### 1. REGISTER_ACK - 注册确认

#### 使用场景
- 客户端发送 REGISTER 消息后，Gateway 返回 REGISTER_ACK 确认注册结果
- 用于通知客户端是否成功注册，以及分配的会话信息

#### 接口定义
```typescript
export interface RegisterAckMessage extends BaseMessage {
  type: MessageType.REGISTER_ACK;
  clientId: string;              // 确认的客户端ID
  success: boolean;              // 注册是否成功
  sessionId?: string;            // 成功时分配的会话ID
  error?: {                      // 失败时的错误信息
    code: string;
    message: string;
  };
  serverInfo?: {                 // 服务器信息
    version: string;
    capabilities: string[];
    currentLoad?: number;        // 当前负载
    maxClients?: number;         // 最大客户端数
  };
}
```

#### 交互流程
```
Client                  Gateway
  |                        |
  | 1. REGISTER            |
  |----------------------->|
  |                        | 2. 验证客户端信息
  |                        | 3. 分配资源
  | 4. REGISTER_ACK        |
  |<-----------------------|
  |                        |
```

### 2. UNREGISTER_ACK - 注销确认

#### 使用场景
- 客户端主动断开连接前发送 UNREGISTER 消息
- Gateway 清理资源后返回 UNREGISTER_ACK 确认

#### 接口定义
```typescript
export interface UnregisterMessage extends BaseMessage {
  type: MessageType.UNREGISTER;
  clientId: string;
  reason?: string;               // 注销原因
}

export interface UnregisterAckMessage extends BaseMessage {
  type: MessageType.UNREGISTER_ACK;
  clientId: string;
  success: boolean;
  cleanupInfo?: {                // 清理信息
    messagesProcessed: number;   // 已处理的消息数
    pendingMessages: number;     // 待处理的消息数
    connectionDuration: number;  // 连接持续时间（秒）
  };
}
```

#### 交互流程
```
Client                  Gateway
  |                        |
  | 1. UNREGISTER          |
  |----------------------->|
  |                        | 2. 停止接收新消息
  |                        | 3. 处理待处理消息
  |                        | 4. 清理资源
  | 5. UNREGISTER_ACK      |
  |<-----------------------|
  | 6. 关闭连接            |
  |----------------------->|
```

### 3. HEARTBEAT_ACK - 心跳确认

#### 使用场景
- 用于精确测量网络延迟
- 确认双向连接正常
- 携带服务器状态信息

#### 接口定义
```typescript
export interface HeartbeatMessage extends BaseMessage {
  type: MessageType.HEARTBEAT;
  clientId: string;
  sequence: number;              // 序列号，用于匹配请求和响应
  clientTime: string;            // 客户端时间戳
}

export interface HeartbeatAckMessage extends BaseMessage {
  type: MessageType.HEARTBEAT_ACK;
  clientId: string;
  sequence: number;              // 原始序列号
  clientTime: string;            // 原始客户端时间
  serverTime: string;            // 服务器时间
  latency?: number;              // 服务器处理延迟（毫秒）
  serverStatus?: {               // 服务器状态
    healthy: boolean;
    activeConnections: number;
    messageQueueSize: number;
    cpuUsage?: number;
    memoryUsage?: number;
  };
}
```

#### 交互流程
```
Client                  Gateway
  |                        |
  | 1. HEARTBEAT           |
  |   (seq=123)            |
  |----------------------->|
  |                        | 2. 记录接收时间
  |                        | 3. 检查系统状态
  | 4. HEARTBEAT_ACK       |
  |   (seq=123)            |
  |<-----------------------|
  | 5. 计算往返延迟        |
  |                        |
```

## 实现示例

### 1. Gateway 端实现

```typescript
class GatewayAckHandler {
  // 处理注册消息
  async handleRegister(ws: WebSocket, msg: RegisterMessage): Promise<void> {
    try {
      // 验证客户端
      const validation = await this.validateClient(msg);
      
      if (validation.success) {
        // 注册成功
        const sessionId = this.generateSessionId();
        this.registerClient(msg.clientId, sessionId, ws);
        
        const ackMessage: RegisterAckMessage = {
          type: MessageType.REGISTER_ACK,
          clientId: msg.clientId,
          success: true,
          sessionId,
          serverInfo: {
            version: '1.0',
            capabilities: ['command', 'batch', 'complex'],
            currentLoad: this.getCurrentLoad(),
            maxClients: this.maxClients
          },
          timestamp: new Date().toISOString(),
          version: '1.0'
        };
        
        ws.send(JSON.stringify(ackMessage));
      } else {
        // 注册失败
        const ackMessage: RegisterAckMessage = {
          type: MessageType.REGISTER_ACK,
          clientId: msg.clientId,
          success: false,
          error: {
            code: validation.errorCode,
            message: validation.errorMessage
          },
          timestamp: new Date().toISOString(),
          version: '1.0'
        };
        
        ws.send(JSON.stringify(ackMessage));
      }
    } catch (error) {
      // 处理异常
      this.sendErrorAck(ws, msg.clientId, error);
    }
  }
  
  // 处理心跳消息
  handleHeartbeat(ws: WebSocket, msg: HeartbeatMessage): void {
    const serverTime = new Date().toISOString();
    const receiveTime = Date.now();
    
    // 计算服务器处理延迟
    const latency = receiveTime - new Date(msg.timestamp).getTime();
    
    const ackMessage: HeartbeatAckMessage = {
      type: MessageType.HEARTBEAT_ACK,
      clientId: msg.clientId,
      sequence: msg.sequence,
      clientTime: msg.clientTime,
      serverTime,
      latency,
      serverStatus: {
        healthy: true,
        activeConnections: this.getActiveConnections(),
        messageQueueSize: this.getQueueSize(),
        cpuUsage: this.getCpuUsage(),
        memoryUsage: this.getMemoryUsage()
      },
      timestamp: serverTime,
      version: '1.0'
    };
    
    ws.send(JSON.stringify(ackMessage));
  }
}
```

### 2. 客户端实现

```typescript
class ClientAckHandler {
  private pendingAcks = new Map<string, PendingAck>();
  
  // 发送注册消息并等待 ACK
  async register(): Promise<RegisterAckMessage> {
    const registerMsg: RegisterMessage = {
      type: MessageType.REGISTER,
      clientId: this.clientId,
      clientType: this.clientType,
      clientInfo: {
        version: '1.0.0',
        platform: 'node',
        capabilities: ['command', 'batch']
      },
      timestamp: new Date().toISOString(),
      version: '1.0'
    };
    
    // 发送并等待 ACK
    return await this.sendAndWaitForAck(
      registerMsg,
      MessageType.REGISTER_ACK,
      5000 // 5秒超时
    );
  }
  
  // 发送心跳并测量延迟
  async sendHeartbeat(): Promise<number> {
    const sequence = this.nextSequence++;
    const clientTime = new Date().toISOString();
    const sendTime = Date.now();
    
    const heartbeatMsg: HeartbeatMessage = {
      type: MessageType.HEARTBEAT,
      clientId: this.clientId,
      sequence,
      clientTime,
      timestamp: clientTime,
      version: '1.0'
    };
    
    const ack = await this.sendAndWaitForAck(
      heartbeatMsg,
      MessageType.HEARTBEAT_ACK,
      3000
    ) as HeartbeatAckMessage;
    
    // 计算往返时间
    const rtt = Date.now() - sendTime;
    
    // 更新服务器状态
    this.updateServerStatus(ack.serverStatus);
    
    return rtt;
  }
  
  // 优雅断开连接
  async disconnect(): Promise<void> {
    const unregisterMsg: UnregisterMessage = {
      type: MessageType.UNREGISTER,
      clientId: this.clientId,
      reason: 'Client shutdown',
      timestamp: new Date().toISOString(),
      version: '1.0'
    };
    
    try {
      const ack = await this.sendAndWaitForAck(
        unregisterMsg,
        MessageType.UNREGISTER_ACK,
        5000
      ) as UnregisterAckMessage;
      
      console.log('Disconnected gracefully:', ack.cleanupInfo);
    } catch (error) {
      console.error('Disconnect error:', error);
    } finally {
      this.ws.close();
    }
  }
}
```

## 使用场景详解

### 1. 连接建立流程

```typescript
// 客户端
async function connectToGateway() {
  const client = new WebSocketClient('ws://gateway:18081');
  
  try {
    // 1. 建立 WebSocket 连接
    await client.connect();
    
    // 2. 发送注册消息并等待确认
    const registerAck = await client.register();
    
    if (!registerAck.success) {
      throw new Error(`Registration failed: ${registerAck.error.message}`);
    }
    
    // 3. 保存会话信息
    client.sessionId = registerAck.sessionId;
    console.log(`Connected with session: ${registerAck.sessionId}`);
    
    // 4. 启动心跳
    client.startHeartbeat();
    
  } catch (error) {
    console.error('Connection failed:', error);
    throw error;
  }
}
```

### 2. 网络质量监控

```typescript
class NetworkMonitor {
  private rttHistory: number[] = [];
  private readonly maxHistory = 100;
  
  async monitorNetwork(client: WebSocketClient): Promise<void> {
    setInterval(async () => {
      try {
        const rtt = await client.sendHeartbeat();
        this.rttHistory.push(rtt);
        
        if (this.rttHistory.length > this.maxHistory) {
          this.rttHistory.shift();
        }
        
        // 分析网络质量
        const avgRtt = this.calculateAverage(this.rttHistory);
        const jitter = this.calculateJitter(this.rttHistory);
        
        if (avgRtt > 1000 || jitter > 200) {
          console.warn('Poor network quality detected', {
            averageRtt: avgRtt,
            jitter: jitter
          });
        }
      } catch (error) {
        console.error('Heartbeat failed:', error);
        // 可能需要重连
      }
    }, 30000); // 30秒一次
  }
}
```

### 3. 负载均衡决策

```typescript
class LoadBalancer {
  private gateways: GatewayInfo[] = [];
  
  // 根据 REGISTER_ACK 中的服务器信息选择最优网关
  selectBestGateway(): GatewayInfo {
    // 收集所有网关的负载信息
    const availableGateways = this.gateways.filter(gw => {
      return gw.lastAck && gw.lastAck.serverInfo;
    });
    
    // 选择负载最低的网关
    return availableGateways.reduce((best, current) => {
      const bestLoad = best.lastAck.serverInfo.currentLoad || 0;
      const currentLoad = current.lastAck.serverInfo.currentLoad || 0;
      return currentLoad < bestLoad ? current : best;
    });
  }
}
```

### 4. 故障检测和恢复

```typescript
class ConnectionManager {
  private missedHeartbeats = 0;
  private readonly maxMissedHeartbeats = 3;
  
  async checkConnection(): Promise<void> {
    try {
      await this.client.sendHeartbeat();
      this.missedHeartbeats = 0;
    } catch (error) {
      this.missedHeartbeats++;
      
      if (this.missedHeartbeats >= this.maxMissedHeartbeats) {
        console.error('Connection lost, attempting reconnect...');
        await this.reconnect();
      }
    }
  }
  
  async reconnect(): Promise<void> {
    // 1. 关闭现有连接
    this.client.close();
    
    // 2. 等待一段时间
    await this.delay(5000);
    
    // 3. 重新连接
    await this.client.connect();
    
    // 4. 重新注册
    const ack = await this.client.register();
    if (ack.success) {
      console.log('Reconnected successfully');
      this.missedHeartbeats = 0;
    }
  }
}
```

## 优势

1. **可靠性保证** - 确保消息被正确接收和处理
2. **状态同步** - 客户端和服务器保持状态一致
3. **性能监控** - 通过心跳 ACK 监控网络延迟
4. **优雅关闭** - 确保资源正确清理
5. **错误处理** - 明确的错误反馈机制

## 注意事项

1. **超时处理** - 所有等待 ACK 的操作都应设置合理的超时时间
2. **重试机制** - 对于关键操作（如注册），应实现重试逻辑
3. **资源清理** - 超时或失败时要清理待处理的 ACK 请求
4. **性能影响** - ACK 机制会增加消息往返，需要权衡可靠性和性能