# WebSocket 协议统一迁移指南

## 概述

本指南帮助将 Gateway 和 Backend 迁移到统一的 WebSocket 协议（v2.0）。新协议设计为向后兼容，支持渐进式升级。

## 主要变更

### 1. 注册消息的统一

**当前差异:**
- Gateway: 只需要 `type` 和 `clientId`
- Backend: 需要 `clientType`、`clientInfo` 等额外字段

**统一方案:**
```typescript
// 简单注册（向后兼容）
{
  "type": "REGISTER",
  "clientId": "device001"
}

// 完整注册（新协议）
{
  "type": "REGISTER",
  "clientId": "backend-server",
  "clientType": "BACKEND",
  "clientInfo": {
    "version": "1.0.0",
    "platform": "nodejs",
    "capabilities": ["command", "program"]
  },
  "timestamp": "2024-01-01T00:00:00Z",
  "version": "2.0"
}
```

### 2. 命令状态的统一

**当前差异:**
- Gateway: 包含 `in_progress` 状态
- Backend: 不包含 `in_progress` 状态

**统一方案:**
- 所有状态都被支持，组件可选择性使用

## 迁移步骤

### 第一阶段：添加协议包依赖

1. **安装共享协议包**
```bash
# 在 Gateway 项目
cd jrsoft-subway-gateway
npm install ../jrsoft-subway-protocol

# 在 Backend 项目  
cd jrsoft-subway-backend
npm install ../jrsoft-subway-protocol

# 在 Edge 项目
cd jrsoft-subway-edge
npm install ../jrsoft-subway-protocol
```

### 第二阶段：更新 Gateway（保持向后兼容）

1. **更新消息处理器以支持扩展字段**
```typescript
// src/ws/websocket-handler.ts
import { RegisterMessage, MessageValidator } from '@jrsoft/subway-protocol';

private handleRegister(ws: WebSocket, message: RegisterMessage) {
  const { clientId, clientType, clientInfo } = message;
  
  // 存储扩展信息（如果提供）
  const client = {
    ws,
    clientId,
    clientType: clientType || 'device',  // 默认为device
    clientInfo: clientInfo || {},
    registeredAt: new Date()
  };
  
  this.clients.set(clientId, client);
  
  // 发送确认，包含sessionId
  const ack = {
    type: 'register_ack',
    clientId,
    success: true,
    sessionId: generateSessionId(),
    timestamp: new Date().toISOString()
  };
  
  ws.send(JSON.stringify(ack));
}
```

2. **添加协议版本协商**
```typescript
// 在连接建立时检查协议版本
ws.on('message', (data) => {
  const message = JSON.parse(data.toString());
  
  // 记录客户端协议版本
  if (message.version) {
    ws.protocolVersion = message.version;
  }
  
  // 处理消息...
});
```

### 第三阶段：更新 Backend（使用新协议）

1. **使用共享协议定义**
```typescript
// src/services/gateway.service.ts
import { 
  MessageFactory, 
  MessageType, 
  ClientType 
} from '@jrsoft/subway-protocol';

private registerWithGateway() {
  const registerMsg = MessageFactory.createRegisterMessage(
    this.clientId,
    ClientType.BACKEND,
    {
      version: '1.0.0',
      platform: 'nodejs',
      capabilities: ['command', 'program']
    }
  );
  
  this.ws.send(JSON.stringify(registerMsg));
}
```

2. **处理简化的响应**
```typescript
private handleMessage(data: any) {
  const message = JSON.parse(data);
  
  switch (message.type) {
    case 'register_ack':
      // 检查是否有sessionId（新协议）
      if (message.sessionId) {
        this.sessionId = message.sessionId;
      }
      break;
    // ...
  }
}
```

### 第四阶段：测试和验证

1. **创建协议兼容性测试**
```typescript
// test/protocol-compatibility.test.ts
describe('Protocol Compatibility', () => {
  it('should handle v1.0 simple registration', async () => {
    const msg = { type: 'register', clientId: 'test' };
    // 验证Gateway能处理
  });
  
  it('should handle v2.0 full registration', async () => {
    const msg = MessageFactory.createRegisterMessage(
      'test',
      ClientType.BACKEND,
      { version: '1.0.0' }
    );
    // 验证Gateway能处理
  });
});
```

## 协议实现要求

1. **支持两种注册格式**
   - 简单格式：仅 `type` 和 `clientId`
   - 完整格式：包含所有扩展字段

2. **使用统一的消息类型**
   - 使用 MessageType 枚举确保类型安全
   - 避免硬编码字符串

3. **处理可选字段**
   - `timestamp`、`version` 等字段为可选
   - 缺失时使用合理的默认值

## 监控和回滚计划

1. **添加协议版本监控**
```typescript
// 记录每个连接的协议版本
logger.info('Client connected', {
  clientId,
  protocolVersion: message.version || '1.0',
  clientType: message.clientType || 'unknown'
});
```

2. **准备回滚脚本**
   - 保留旧的协议处理代码
   - 通过特性开关控制新协议启用

## 时间表

- **第1周**: 部署更新的 Gateway（向后兼容）
- **第2周**: 逐步升级 Backend 使用新协议
- **第3周**: 升级 Edge 和其他客户端
- **第4周**: 监控和优化

## 常见问题

**Q: 旧版本客户端会受影响吗？**
A: 不会。新协议完全向后兼容，旧客户端可继续使用简单注册。

**Q: 如何知道客户端使用的协议版本？**
A: 检查消息中的 `version` 字段，缺失则为 v1.0。

**Q: 性能会受影响吗？**
A: 几乎没有影响。额外字段是可选的，不会增加必需的网络开销。