# ProtocolUtils 使用指南

## 概述

`ProtocolUtils` 提供了一系列工具方法，用于处理协议中的枚举转换、消息类型判断和请求引用管理。

## 功能分类

### 1. 状态和枚举转换

#### 基础转换方法

```typescript
import { ProtocolUtils, CommandStatus, Priority, ClientType } from '@jrsoft/subway-protocol';

// CommandStatus 转换
const status = ProtocolUtils.stringToStatus('completed'); // => CommandStatus.COMPLETED
const statusStr = ProtocolUtils.statusToString(CommandStatus.FAILED); // => 'FAILED'

// Priority 转换
const priority = ProtocolUtils.priorityToEnum('high'); // => Priority.HIGH
const priorityStr = ProtocolUtils.enumToPriority(Priority.CRITICAL); // => 'CRITICAL'

// ClientType 转换
const clientType = ProtocolUtils.clientTypeToEnum('device'); // => ClientType.DEVICE
const typeStr = ProtocolUtils.enumToClientType(ClientType.BACKEND); // => 'BACKEND'
```

#### 安全转换方法（不抛出异常）

```typescript
// 返回枚举值或 null
const status = ProtocolUtils.tryParseStatus('invalid'); // => null
const priority = ProtocolUtils.tryParsePriority('HIGH'); // => Priority.HIGH
const clientType = ProtocolUtils.tryParseClientType('backend'); // => ClientType.BACKEND
```

### 2. 消息类型判断

增强的类型判断方法，不仅检查类型还验证结构：

```typescript
// 检查是否为命令消息
if (ProtocolUtils.isCommandMessage(message)) {
  // TypeScript 知道 message 是 CommandMessage
  console.log(message.command.commandCode);
}

// 检查是否为进度更新
if (ProtocolUtils.isProgressUpdate(message)) {
  console.log(`Progress: ${message.progress}%`);
}

// 检查是否为程序消息
if (ProtocolUtils.isProgramMessage(message)) {
  console.log(message.command.parameters.programName);
}
```

### 3. 请求引用管理

#### 生成请求引用

```typescript
// 基础生成
const ref1 = ProtocolUtils.generateRequestRef(); 
// => "1703123456789-a1b2c3d4e"

// 带前缀生成
const ref2 = ProtocolUtils.generateRequestRef('backend');
// => "backend-1703123456789-f5g6h7i8j"

// 结构化生成
const ref3 = ProtocolUtils.generateStructuredRequestRef('gateway', 'sendCommand');
// => "gateway:sendcommand:1703123456789:k9l0m1"
```

#### 提取和解析请求引用

```typescript
// 从消息中提取请求引用
const requestRef = ProtocolUtils.extractRequestRef(message);

// 解析请求引用
const parsed = ProtocolUtils.parseRequestRef('backend-1703123456789-a1b2c3d4e');
// => { prefix: 'backend', timestamp: 1703123456789, random: 'a1b2c3d4e' }

const structured = ProtocolUtils.parseRequestRef('gateway:sendcommand:1703123456789:k9l0m1');
// => { service: 'gateway', operation: 'sendcommand', timestamp: 1703123456789, random: 'k9l0m1' }
```

### 4. 辅助方法

```typescript
// 获取消息类型的友好名称
const typeName = ProtocolUtils.getMessageTypeName(message);
// => "Command Response"

// 检查是否为请求消息（需要响应）
if (ProtocolUtils.isRequestMessage(message)) {
  // 处理需要响应的消息
}

// 检查是否为响应消息
if (ProtocolUtils.isResponseMessage(message)) {
  // 处理响应消息
}
```

## 实际使用场景

### 场景 1：处理外部 API 数据

```typescript
// 从 REST API 接收的数据
const apiData = {
  status: 'completed',  // 小写
  priority: 'HIGH',
  client_type: 'backend'  // 下划线格式
};

// 转换为协议格式
const command = {
  status: ProtocolUtils.stringToStatus(apiData.status),
  priority: ProtocolUtils.priorityToEnum(apiData.priority),
  clientType: ProtocolUtils.clientTypeToEnum(apiData.client_type.replace('_', ''))
};
```

### 场景 2：请求追踪和日志

```typescript
class CommandService {
  async sendCommand(command: Command, targetClientId: string) {
    // 生成可追踪的请求 ID
    const requestRef = ProtocolUtils.generateStructuredRequestRef('backend', 'command');
    
    const message = MessageFactory.createCommandMessage(
      requestRef,
      targetClientId,
      command,
      '/api/callback'
    );
    
    logger.info(`Sending command ${requestRef}`);
    
    try {
      const response = await this.gateway.send(message);
      
      // 从响应中提取请求引用进行关联
      const responseRef = ProtocolUtils.extractRequestRef(response);
      logger.info(`Received response for ${responseRef}`);
      
    } catch (error) {
      logger.error(`Command ${requestRef} failed:`, error);
    }
  }
}
```

### 场景 3：消息路由和处理

```typescript
class MessageRouter {
  handleMessage(message: AnyMessage) {
    // 获取友好的消息类型名称用于日志
    const messageType = ProtocolUtils.getMessageTypeName(message);
    logger.info(`Processing ${messageType} message`);
    
    // 根据消息类型路由
    if (ProtocolUtils.isRequestMessage(message)) {
      this.handleRequest(message);
    } else if (ProtocolUtils.isResponseMessage(message)) {
      this.handleResponse(message);
    } else if (ProtocolUtils.isProgressUpdate(message)) {
      this.handleProgress(message as ProgressUpdateMessage);
    }
  }
  
  private handleProgress(message: ProgressUpdateMessage) {
    const requestRef = ProtocolUtils.extractRequestRef(message);
    const parsed = ProtocolUtils.parseRequestRef(requestRef!);
    
    if (parsed?.service === 'backend') {
      // 处理来自 backend 的进度更新
      this.notifyBackendProgress(message);
    }
  }
}
```

### 场景 4：错误处理和重试

```typescript
class ErrorHandler {
  handleError(error: any, originalMessage?: AnyMessage) {
    let errorMessage: ErrorMessage;
    
    if (error.code && error.message) {
      // 创建错误消息
      errorMessage = MessageFactory.createErrorMessage(
        error.code,
        error.message,
        originalMessage ? ProtocolUtils.extractRequestRef(originalMessage) : undefined
      );
    }
    
    // 安全地转换错误级别
    const severity = ProtocolUtils.tryParseStatus(error.severity || 'FAILED');
    if (severity) {
      // 处理特定严重程度的错误
    }
  }
}
```

### 场景 5：协议版本兼容

```typescript
class LegacyAdapter {
  // 处理旧版本的消息格式
  adaptLegacyMessage(legacyMsg: any): AnyMessage | null {
    // 旧版本可能使用不同的状态值
    const status = this.mapLegacyStatus(legacyMsg.status);
    const modernStatus = ProtocolUtils.tryParseStatus(status);
    
    if (!modernStatus) {
      logger.warn(`Unknown legacy status: ${legacyMsg.status}`);
      return null;
    }
    
    // 构建现代消息格式
    // ...
  }
  
  private mapLegacyStatus(legacyStatus: string): string {
    const mapping: Record<string, string> = {
      'done': 'COMPLETED',
      'error': 'FAILED',
      'pending': 'IN_PROGRESS'
    };
    
    return mapping[legacyStatus] || legacyStatus;
  }
}
```

## 最佳实践

1. **使用安全转换方法处理不可信输入**
   ```typescript
   const status = ProtocolUtils.tryParseStatus(userInput) || CommandStatus.FAILED;
   ```

2. **生成结构化的请求引用便于追踪**
   ```typescript
   const ref = ProtocolUtils.generateStructuredRequestRef(serviceName, operationName);
   ```

3. **使用增强的类型判断进行完整验证**
   ```typescript
   if (ProtocolUtils.isCommandMessage(message)) {
     // 不仅类型正确，结构也已验证
   }
   ```

4. **在日志中使用友好的消息类型名称**
   ```typescript
   logger.info(`${ProtocolUtils.getMessageTypeName(message)} processed`);
   ```

5. **解析请求引用以获取上下文信息**
   ```typescript
   const parsed = ProtocolUtils.parseRequestRef(requestRef);
   if (parsed?.service === 'critical-service') {
     // 优先处理关键服务的请求
   }
   ```