# Simple 命令执行流程详解

## 概述

Simple 类型命令是 JRSoft Subway 协议中最基本的命令类型，遵循"一次请求，一次响应"的模式。

## 执行流程

### 标准执行流程

所有设备都通过 Edge 接入系统，Gateway 负责路由到正确的 Edge：

```
┌─────────┐    ┌─────────┐    ┌──────┐    ┌────────┐
│ Backend │    │ Gateway │    │ Edge │    │ Device │
└────┬────┘    └────┬────┘    └───┬──┘    └────┬───┘
     │              │              │            │
     │ 1. command   │              │            │
     │ (edge01:td01)│              │            │
     ├─────────────►│              │            │
     │              │              │            │
     │              │ 2. route to  │            │
     │              │    edge01    │            │
     │              ├─────────────►│            │
     │              │              │            │
     │              │              │ 3. forward │
     │              │              │   to td01  │
     │              │              ├───────────►│
     │              │              │            │
     │              │              │            │ 4. execute
     │              │              │            ├─┐
     │              │              │            │ │
     │              │              │            │◄┘
     │              │              │            │
     │              │              │ 5. response│
     │              │              │◄───────────┤
     │              │              │            │
     │              │ 6. response  │            │
     │              │◄─────────────┤            │
     │              │              │            │
     │ 7. response  │              │            │
     │◄─────────────┤              │            │
     │              │              │            │
```

## 关键组件职责

### Backend
- 发起命令请求
- 指定目标设备（targetClientId = deviceId）
- 设置超时和优先级
- 处理命令响应

### Gateway（中央路由器）
- **路由查找**：根据设备ID查找对应的Edge节点
- **连接管理**：维护与多个 Edge 的WebSocket连接
- **超时控制**：监控命令执行超时
- **响应路由**：根据 requestRef 将响应路由回发起方
- **回调处理**：如配置了 callback URL，推送响应
- **负载均衡**：可选，在多个 Edge 之间分配负载

### Edge（设备接入点）
- **设备管理**：管理本地多个设备的连接
- **本地路由**：根据 targetClientId（设备ID）路由到设备
- **协议转换**：可选，将WebSocket协议转换为设备协议
- **状态监控**：监控本地设备健康状态
- **断线重连**：处理设备的连接恢复

### Device
- **命令执行**：执行具体的硬件操作
- **响应生成**：生成执行结果
- **错误处理**：处理执行异常
- **状态上报**：定期向 Edge 汇报状态

## 消息格式

### 命令请求
```json
{
  "type": "COMMAND",
  "requestRef": "cmd-${timestamp}-${random}",  // 唯一标识
  "targetClientId": "td-01",              // 设备ID
  "command": {
    "commandType": "SIMPLE",
    "commandCode": "SET_COLOR",
    "deviceType": "pillar",
    "deviceId": 1,
    "operationType": "WRITE",
    "parameters": {
      "color": "#FF0000"
    }
  },
  "priority": "NORMAL",     // low, normal, high, critical
  "timeout": 10000,         // 毫秒
  "callback": "http://backend/api/callback/cmd-123",  // 可选
  "timestamp": "2024-01-20T10:00:00Z",
  "version": "1.0"
}
```

### 命令响应
```json
{
  "type": "COMMAND_RESPONSE",
  "requestRef": "cmd-${timestamp}-${random}",  // 与请求相同
  "status": "COMPLETED",                       // 执行状态
  "result": {
    "deviceType": "pillar",
    "deviceId": 1,
    "commandCode": "SET_COLOR",
    "operationType": "WRITE",
    "data": {
      // 成功时返回执行结果
      "previousColor": "#00FF00",
      "currentColor": "#FF0000"
    }
  },
  "executionTime": 150,  // 执行耗时（毫秒）
  "timestamp": "2024-01-20T10:00:00.150Z",
  "version": "1.0"
}
```

## targetClientId 格式

```
格式: 直接使用设备ID
示例: 
- "td-01" - 设备ID，Gateway自动查找对应的Edge
- "screen-05" - 5号屏幕设备
- "pillar-123" - 123号光柱设备
```

**路由流程：**
1. Gateway 收到 targetClientId = "td-01"，查找路由表
2. Gateway 发现 td-01 在 edge-001 节点下
3. Gateway 将命令路由到 edge-001
4. Edge 收到命令，targetClientId 就是设备ID
5. Edge 将命令转发到设备 td-01

## 超时处理

1. **Backend设置超时**：在命令中指定 timeout 字段
2. **Gateway监控超时**：
   ```javascript
   setTimeout(() => {
     if (!hasResponse) {
       sendTimeoutResponse(requestRef);
     }
   }, command.timeout);
   ```
3. **超时响应**：
   ```json
   {
     "type": "COMMAND_RESPONSE",
     "requestRef": "cmd-123",
     "status": "TIMEOUT",
     "log": {
       "level": "ERROR",
       "message": "Command execution timeout",
       "code": "COMMAND_TIMEOUT",
       "data": {
         "timeout": 10000,
         "elapsed": 10500
       }
     }
   }
   ```

## 错误处理

### Edge 不存在
```json
{
  "type": "ERROR",
  "requestRef": "cmd-123",
  "code": "EDGE_NOT_FOUND",
  "message": "Target edge edge-999 not found",
  "details": {
    "targetClientId": "td-01",
    "requestedEdge": "edge-999",
    "availableEdges": ["edge-001", "edge-002"]
  }
}
```

### 设备离线
```json
{
  "type": "COMMAND_RESPONSE",
  "requestRef": "cmd-123",
  "status": "FAILED",
  "log": {
    "level": "ERROR",
    "message": "Device td-01 is offline at edge-001",
    "code": "DEVICE_OFFLINE",
    "data": {
      "edgeId": "edge-001",
      "deviceId": "td-01",
      "lastSeen": "2024-01-20T09:55:00Z"
    }
  }
}
```

### 执行失败
```json
{
  "type": "COMMAND_RESPONSE",
  "requestRef": "cmd-123",
  "status": "FAILED",
  "result": {
    "deviceType": "pillar",
    "deviceId": 1,
    "commandCode": "SET_COLOR",
    "operationType": "WRITE",
    "data": {
      "Uerror": "Hardware malfunction",
      "errorCode": "HW_ERROR_001"
    }
  }
}
```

## 最佳实践

### 1. RequestRef 生成
```javascript
function generateRequestRef(prefix = 'cmd') {
  const timestamp = Date.now();
  const random = Math.random().toString(36).substr(2, 9);
  return `${prefix}-${timestamp}-${random}`;
}
```

### 2. 超时设置建议
- 读操作：5-10秒
- 写操作：10-30秒
- 复杂操作：30-60秒

### 3. 错误重试
```javascript
async function executeWithRetry(command, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      const response = await sendCommand(command);
      if (response.status === 'completed') {
        return response;
      }
      
      // 仅在特定错误时重试
      if (!isRetryableError(response)) {
        return response;
      }
    } catch (error) {
      if (i === maxRetries - 1) throw error;
    }
    
    // 指数退避
    await sleep(Math.pow(2, i) * 1000);
  }
}
```

### 4. 设备端实现
```javascript
class DeviceHandler {
  async handleCommand(message) {
    // 只处理 simple 命令
    if (message.command.commandType !== 'simple') {
      throw new Error('Device only supports simple commands');
    }
    
    try {
      // 执行命令
      const result = await this.executeCommand(message.command);
      
      // 返回成功响应
      return {
        type: 'command_response',
        requestRef: message.requestRef,
        status: 'completed',
        result: {
          deviceType: message.command.deviceType,
          deviceId: message.command.deviceId,
          commandCode: message.command.commandCode,
          operationType: message.command.operationType,
          data: result
        },
        executionTime: Date.now() - startTime,
        timestamp: new Date().toISOString(),
        version: '1.0'
      };
    } catch (error) {
      // 返回错误响应
      return {
        type: 'command_response',
        requestRef: message.requestRef,
        status: 'failed',
        result: {
          deviceType: message.command.deviceType,
          deviceId: message.command.deviceId,
          commandCode: message.command.commandCode,
          operationType: message.command.operationType,
          data: {
            error: error.message,
            errorCode: error.code
          }
        },
        log: {
          level: 'error',
          message: error.message,
          code: error.code
        },
        timestamp: new Date().toISOString(),
        version: '1.0'
      };
    }
  }
}
```

## 总结

Simple 命令是整个协议的基础，具有以下特点：

1. **简单直接**：一次请求，一次响应
2. **路由透明**：Backend无需知道Edge拓扑，Gateway自动路由
3. **错误处理完善**：超时、离线、执行失败都有明确处理
4. **扩展性好**：通过 parameters 支持各种命令参数

其他命令类型（Batch、Complex）最终都会分解为 Simple 命令执行，这保证了设备端实现的简单性。