|
1 | 1 | using System; |
2 | 2 | using System.Collections.Generic; |
| 3 | +using System.IO; |
3 | 4 | using System.Linq; |
4 | 5 | using System.Reflection; |
5 | 6 | using System.Text; |
6 | 7 | using System.Text.Json; |
| 8 | +using System.Threading; |
7 | 9 | using System.Threading.Tasks; |
8 | 10 | using Cyaim.WebSocketServer.Infrastructure.Configures; |
9 | 11 | using Cyaim.WebSocketServer.Infrastructure.Metrics; |
@@ -453,6 +455,108 @@ public async Task<Dictionary<string, bool>> RouteObjectsAsync<T>( |
453 | 455 |
|
454 | 456 | #endregion |
455 | 457 |
|
| 458 | + #region Stream Routing Methods / 流路由方法 |
| 459 | + |
| 460 | + /// <summary> |
| 461 | + /// Route stream to connection(s) - automatically handles single machine or cluster mode (supports chunked transmission) |
| 462 | + /// 将流转发到连接 - 自动处理单机或集群模式(支持分块传输) |
| 463 | + /// </summary> |
| 464 | + /// <param name="connectionId">Connection ID / 连接 ID</param> |
| 465 | + /// <param name="stream">Stream to send / 要发送的流</param> |
| 466 | + /// <param name="messageType">WebSocket message type / WebSocket 消息类型</param> |
| 467 | + /// <param name="chunkSize">Chunk size in bytes (default: 64KB) / 块大小(字节,默认:64KB)</param> |
| 468 | + /// <param name="cancellationToken">Cancellation token / 取消令牌</param> |
| 469 | + /// <returns>True if routed successfully / 路由成功返回 true</returns> |
| 470 | + /// <remarks> |
| 471 | + /// This method reads the stream in chunks and sends them sequentially. |
| 472 | + /// For cluster mode, it automatically forwards chunks to the correct node. |
| 473 | + /// 此方法以块为单位读取流并顺序发送。 |
| 474 | + /// 对于集群模式,它会自动将块转发到正确的节点。 |
| 475 | + /// </remarks> |
| 476 | + public async Task<bool> RouteStreamAsync( |
| 477 | + string connectionId, |
| 478 | + Stream stream, |
| 479 | + WebSocketMessageType messageType = WebSocketMessageType.Binary, |
| 480 | + int chunkSize = 64 * 1024, |
| 481 | + CancellationToken cancellationToken = default) |
| 482 | + { |
| 483 | + if (string.IsNullOrEmpty(connectionId) || stream == null || !stream.CanRead) |
| 484 | + { |
| 485 | + return false; |
| 486 | + } |
| 487 | + |
| 488 | + return await _router.RouteStreamAsync(connectionId, stream, (int)messageType, chunkSize, cancellationToken); |
| 489 | + } |
| 490 | + |
| 491 | + /// <summary> |
| 492 | + /// Route stream to multiple connections - automatically handles single machine or cluster mode (supports chunked transmission) |
| 493 | + /// 将流转发到多个连接 - 自动处理单机或集群模式(支持分块传输) |
| 494 | + /// </summary> |
| 495 | + /// <param name="connectionIds">Connection IDs / 连接 ID 列表</param> |
| 496 | + /// <param name="stream">Stream to send / 要发送的流</param> |
| 497 | + /// <param name="messageType">WebSocket message type / WebSocket 消息类型</param> |
| 498 | + /// <param name="chunkSize">Chunk size in bytes (default: 64KB) / 块大小(字节,默认:64KB)</param> |
| 499 | + /// <param name="cancellationToken">Cancellation token / 取消令牌</param> |
| 500 | + /// <returns>Dictionary of connection ID to routing result / 连接ID到路由结果的字典</returns> |
| 501 | + /// <remarks> |
| 502 | + /// This method reads the stream once and sends chunks to all connections in parallel. |
| 503 | + /// For cluster mode, it automatically forwards chunks to the correct nodes. |
| 504 | + /// 此方法读取流一次,并并行向所有连接发送块。 |
| 505 | + /// 对于集群模式,它会自动将块转发到正确的节点。 |
| 506 | + /// </remarks> |
| 507 | + public async Task<Dictionary<string, bool>> RouteStreamsAsync( |
| 508 | + IEnumerable<string> connectionIds, |
| 509 | + Stream stream, |
| 510 | + WebSocketMessageType messageType = WebSocketMessageType.Binary, |
| 511 | + int chunkSize = 64 * 1024, |
| 512 | + CancellationToken cancellationToken = default) |
| 513 | + { |
| 514 | + if (connectionIds == null || stream == null || !stream.CanRead) |
| 515 | + { |
| 516 | + return new Dictionary<string, bool>(); |
| 517 | + } |
| 518 | + |
| 519 | + var results = new Dictionary<string, bool>(); |
| 520 | + var connectionIdList = connectionIds.Where(id => !string.IsNullOrEmpty(id)).ToList(); |
| 521 | + |
| 522 | + if (connectionIdList.Count == 0) |
| 523 | + { |
| 524 | + return results; |
| 525 | + } |
| 526 | + |
| 527 | + // Read stream once and send to all connections / 读取流一次并发送到所有连接 |
| 528 | + // For multiple connections, we need to read the stream multiple times or buffer it |
| 529 | + // 对于多个连接,我们需要多次读取流或缓冲它 |
| 530 | + // For simplicity, we'll buffer the stream for multiple connections |
| 531 | + // 为简单起见,我们将为多个连接缓冲流 |
| 532 | + if (connectionIdList.Count > 1) |
| 533 | + { |
| 534 | + // Buffer the stream / 缓冲流 |
| 535 | + using var memoryStream = new MemoryStream(); |
| 536 | + await stream.CopyToAsync(memoryStream, cancellationToken); |
| 537 | + memoryStream.Position = 0; |
| 538 | + |
| 539 | + var tasks = connectionIdList.Select(async connectionId => |
| 540 | + { |
| 541 | + memoryStream.Position = 0; |
| 542 | + var success = await _router.RouteStreamAsync(connectionId, memoryStream, (int)messageType, chunkSize, cancellationToken); |
| 543 | + results[connectionId] = success; |
| 544 | + }); |
| 545 | + |
| 546 | + await Task.WhenAll(tasks); |
| 547 | + } |
| 548 | + else |
| 549 | + { |
| 550 | + // Single connection - stream directly / 单个连接 - 直接流式传输 |
| 551 | + var connectionId = connectionIdList[0]; |
| 552 | + results[connectionId] = await _router.RouteStreamAsync(connectionId, stream, (int)messageType, chunkSize, cancellationToken); |
| 553 | + } |
| 554 | + |
| 555 | + return results; |
| 556 | + } |
| 557 | + |
| 558 | + #endregion |
| 559 | + |
456 | 560 | /// <summary> |
457 | 561 | /// Get connection count for this node |
458 | 562 | /// 获取此节点的连接数 |
|
0 commit comments