# 设备端到 Edge 的 WebSocket 协议

## 概述

设备端通过 WebSocket 协议连接到 Edge 节点，使用与 Gateway 相同的协议规范。Edge 在此架构中扮演本地 Gateway 的角色，为设备端提供注册、心跳、命令执行等服务。

## 架构更新

```
┌─────────────────────────────────────────────────┐
│                   Gateway                        │
│         (中央路由和管理服务器)                    │
└─────────────────────────────────────────────────┘
                      ↑
                      │ WebSocket (Edge→Gateway)
                      │
┌─────────────────────────────────────────────────┐
│              Edge Node (edge-001)                │
│         (本地设备管理和代理服务)                  │
│                                                  │
│  ┌───────────────────────────────────────────┐  │
│  │         设备连接管理器                      │  │
│  │  - WebSocket 服务器 (端口: 18083)         │  │
│  │  - 设备注册处理                           │  │
│  │  - 心跳监控                               │  │
│  │  - 命令路由和转发                         │  │
│  └───────────────────────────────────────────┘  │
└─────────────────────────────────────────────────┘
                      ↑
                      │ WebSocket (Device→Edge)
                      │
    ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐
    │设备端1 │ │设备端2 │ │设备端3 │ │设备端4 │
    └───────┘ └───────┘ └───────┘ └───────┘
```

## 设备端注册流程

### 1. 设备端连接到 Edge

```typescript
// 设备端代码示例
const ws = new WebSocket('ws://edge-001:18083');

ws.on('open', () => {
  // 发送注册消息
  const registerMsg = {
    type: 'register',
    clientId: 'device-001',
    clientType: 'device',
    clientInfo: {
      version: '1.0.0',
      deviceType: 'media_player',
      capabilities: ['play', 'stop', 'pause', 'status_report']
    }
  };
  
  ws.send(JSON.stringify(registerMsg));
});
```

### 2. Edge 处理设备注册

```typescript
// Edge 端处理逻辑
class EdgeDeviceHandler {
  private devices = new Map<string, DeviceConnection>();
  
  handleDeviceRegister(ws: WebSocket, message: RegisterMessage) {
    const { clientId, clientInfo } = message;
    
    // 1. 记录设备连接
    this.devices.set(clientId, {
      ws,
      clientId,
      clientInfo,
      registeredAt: new Date(),
      lastHeartbeat: new Date()
    });
    
    // 2. 发送注册确认给设备
    const ack = {
      type: 'register_ack',
      clientId,
      success: true,
      sessionId: generateSessionId(),
      timestamp: new Date().toISOString()
    };
    ws.send(JSON.stringify(ack));
    
    // 3. 如果已连接到 Gateway，代理注册到 Gateway
    if (this.gatewayConnected) {
      this.proxyRegisterToGateway(clientId, clientInfo);
    }
  }
  
  // 代理注册到 Gateway
  proxyRegisterToGateway(deviceId: string, deviceInfo: ClientInfo) {
    const proxyRegister = {
      type: 'register',
      clientId: deviceId,
      clientType: 'device',
      clientInfo: deviceInfo,
      edgeInfo: {
        edgeId: this.edgeId,
        edgeVersion: this.version,
        connectionTime: new Date().toISOString()
      }
    };
    
    this.gatewayWs.send(JSON.stringify(proxyRegister));
  }
}
```

## 心跳机制

### 设备端心跳

设备端需要定期向 Edge 发送心跳，保持连接活跃：

```typescript
// 设备端心跳实现
class DeviceClient {
  private heartbeatInterval: NodeJS.Timer;
  private heartbeatSequence = 0;
  
  startHeartbeat() {
    this.heartbeatInterval = setInterval(() => {
      const heartbeat = {
        type: 'heartbeat',
        clientId: this.clientId,
        sequence: ++this.heartbeatSequence,
        timestamp: new Date().toISOString()
      };
      
      this.ws.send(JSON.stringify(heartbeat));
    }, 30000); // 30秒一次
  }
  
  handleHeartbeatAck(message: HeartbeatAckMessage) {
    // 更新最后确认时间
    this.lastHeartbeatAck = new Date();
  }
}
```

### Edge 心跳监控

Edge 监控所有设备的心跳状态：

```typescript
class EdgeHeartbeatMonitor {
  private readonly HEARTBEAT_TIMEOUT = 90000; // 90秒超时
  
  startMonitoring() {
    setInterval(() => {
      const now = Date.now();
      
      for (const [clientId, device] of this.devices) {
        const lastHeartbeat = device.lastHeartbeat.getTime();
        
        if (now - lastHeartbeat > this.HEARTBEAT_TIMEOUT) {
          this.handleDeviceTimeout(clientId);
        }
      }
    }, 10000); // 每10秒检查一次
  }
  
  handleHeartbeat(clientId: string, message: HeartbeatMessage) {
    const device = this.devices.get(clientId);
    if (device) {
      device.lastHeartbeat = new Date();
      
      // 发送心跳确认
      const ack = {
        type: 'heartbeat_ack',
        clientId,
        sequence: message.sequence
      };
      device.ws.send(JSON.stringify(ack));
    }
  }
  
  handleDeviceTimeout(clientId: string) {
    console.log(`Device ${clientId} heartbeat timeout`);
    
    // 1. 标记设备为离线
    const device = this.devices.get(clientId);
    if (device) {
      device.status = 'offline';
    }
    
    // 2. 通知 Gateway 设备离线
    if (this.gatewayConnected) {
      this.notifyGatewayDeviceOffline(clientId);
    }
    
    // 3. 清理连接
    this.cleanupDevice(clientId);
  }
}
```

## 完整通信流程

### 1. 启动时序

```
设备端启动 → 连接 Edge → 注册 → 开始心跳
                ↓
         Edge 记录设备
                ↓
         Edge 连接 Gateway
                ↓
         Edge 批量注册所有设备到 Gateway
```

### 2. 命令执行流程

```
Backend → Gateway → Edge → Device
   ↑                           ↓
   └───────────────────────────┘
         (响应返回路径)
```

### 3. 状态同步

```typescript
// Edge 定期同步设备状态到 Gateway
class EdgeStatusReporter {
  reportDeviceStatus() {
    const statusReport = {
      type: 'edge_status_report',
      edgeId: this.edgeId,
      devices: Array.from(this.devices.values()).map(device => ({
        clientId: device.clientId,
        status: device.status,
        lastHeartbeat: device.lastHeartbeat,
        clientInfo: device.clientInfo
      })),
      timestamp: new Date().toISOString()
    };
    
    this.gatewayWs.send(JSON.stringify(statusReport));
  }
}
```

## 错误处理

### 1. 设备断线重连

```typescript
// 设备端重连逻辑
class ResilientDeviceClient {
  private reconnectAttempts = 0;
  private maxReconnectAttempts = 10;
  
  connect() {
    this.ws = new WebSocket(this.edgeUrl);
    
    this.ws.on('close', () => {
      if (this.reconnectAttempts < this.maxReconnectAttempts) {
        const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts), 30000);
        setTimeout(() => {
          this.reconnectAttempts++;
          this.connect();
        }, delay);
      }
    });
    
    this.ws.on('open', () => {
      this.reconnectAttempts = 0;
      this.register();
      this.startHeartbeat();
    });
  }
}
```

### 2. Edge 处理设备异常

```typescript
class EdgeDeviceManager {
  handleDeviceError(clientId: string, error: any) {
    console.error(`Device ${clientId} error:`, error);
    
    const device = this.devices.get(clientId);
    if (device) {
      // 发送错误消息给设备
      const errorMsg = {
        type: 'error',
        code: 'DEVICE_ERROR',
        message: error.message,
        retryable: true
      };
      
      try {
        device.ws.send(JSON.stringify(errorMsg));
      } catch (e) {
        // WebSocket 可能已关闭
        this.cleanupDevice(clientId);
      }
    }
  }
}
```

## 性能优化

### 1. 连接池管理

```typescript
class EdgeConnectionPool {
  private readonly MAX_CONNECTIONS = 1000;
  private readonly CONNECTION_TIMEOUT = 300000; // 5分钟
  
  acceptConnection(ws: WebSocket): boolean {
    if (this.devices.size >= this.MAX_CONNECTIONS) {
      // 拒绝新连接
      ws.close(1008, 'Connection limit exceeded');
      return false;
    }
    
    // 清理超时未注册的连接
    this.cleanupStaleConnections();
    
    return true;
  }
}
```

### 2. 消息批处理

```typescript
class EdgeMessageBatcher {
  private messageQueue = new Map<string, any[]>();
  private batchInterval = 100; // 100ms
  
  queueMessage(clientId: string, message: any) {
    if (!this.messageQueue.has(clientId)) {
      this.messageQueue.set(clientId, []);
    }
    
    this.messageQueue.get(clientId)!.push(message);
    
    // 调度批量发送
    this.scheduleBatch(clientId);
  }
  
  private scheduleBatch(clientId: string) {
    setTimeout(() => {
      const messages = this.messageQueue.get(clientId);
      if (messages && messages.length > 0) {
        const batchMessage = {
          type: 'batch',
          messages: messages
        };
        
        const device = this.devices.get(clientId);
        if (device) {
          device.ws.send(JSON.stringify(batchMessage));
        }
        
        this.messageQueue.delete(clientId);
      }
    }, this.batchInterval);
  }
}
```

## 安全考虑

### 1. 设备认证

```typescript
// Edge 可以要求设备提供认证信息
interface AuthenticatedRegisterMessage extends RegisterMessage {
  auth?: {
    token?: string;
    apiKey?: string;
    certificate?: string;
  };
}

class SecureEdgeHandler {
  validateDevice(message: AuthenticatedRegisterMessage): boolean {
    if (!message.auth) {
      return false; // 需要认证
    }
    
    // 验证 token 或 API key
    return this.authService.validate(message.auth);
  }
}
```

### 2. 消息加密

```typescript
// 支持加密通信
class EncryptedDeviceClient {
  sendSecureMessage(message: any) {
    const encrypted = this.encrypt(JSON.stringify(message));
    this.ws.send(encrypted);
  }
  
  handleEncryptedMessage(data: any) {
    const decrypted = this.decrypt(data);
    const message = JSON.parse(decrypted);
    this.handleMessage(message);
  }
}
```

## 总结

设备端到 Edge 的通信使用标准 WebSocket 协议，包括：

1. **注册机制** - 设备向 Edge 注册自己的信息和能力
2. **心跳保活** - 30秒心跳间隔，90秒超时断开
3. **命令执行** - Edge 转发来自 Gateway 的命令
4. **状态同步** - Edge 汇总设备状态上报给 Gateway
5. **错误处理** - 支持断线重连和异常恢复
6. **性能优化** - 连接池管理和消息批处理
7. **安全特性** - 可选的认证和加密支持

这种设计确保了设备端与系统其他部分的无缝集成，同时保持了协议的一致性和可扩展性。