You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
196 lines
6.9 KiB
196 lines
6.9 KiB
using System.Net.WebSockets;
|
|
using CellularManagement.Domain.Entities;
|
|
using CellularManagement.Application.Services;
|
|
using Microsoft.Extensions.Logging;
|
|
using Microsoft.Extensions.Caching.Distributed;
|
|
using System.Text.Json;
|
|
|
|
namespace CellularManagement.Infrastructure.Distributed;
|
|
|
|
public class DistributedWebSocketManager : IWebSocketService
|
|
{
|
|
private readonly IDistributedCache _distributedCache;
|
|
private readonly ILogger<DistributedWebSocketManager> _logger;
|
|
private readonly string _nodeId;
|
|
private const string CONNECTION_PREFIX = "ws_connection_";
|
|
private const string USER_PREFIX = "ws_user_";
|
|
private const string NODE_PREFIX = "ws_node_";
|
|
|
|
public DistributedWebSocketManager(
|
|
IDistributedCache distributedCache,
|
|
ILogger<DistributedWebSocketManager> logger)
|
|
{
|
|
_distributedCache = distributedCache;
|
|
_logger = logger;
|
|
_nodeId = Guid.NewGuid().ToString();
|
|
}
|
|
|
|
public async Task<string> AcceptConnectionAsync(System.Net.WebSockets.WebSocket webSocket)
|
|
{
|
|
var connectionId = Guid.NewGuid().ToString();
|
|
var connection = WebSocketConnection.Create(connectionId);
|
|
|
|
var connectionKey = $"{CONNECTION_PREFIX}{connectionId}";
|
|
var nodeKey = $"{NODE_PREFIX}{_nodeId}";
|
|
|
|
// 存储连接信息
|
|
await _distributedCache.SetStringAsync(
|
|
connectionKey,
|
|
JsonSerializer.Serialize(connection),
|
|
new DistributedCacheEntryOptions
|
|
{
|
|
SlidingExpiration = TimeSpan.FromMinutes(30)
|
|
});
|
|
|
|
// 更新节点连接列表
|
|
await AddConnectionToNodeAsync(connectionId);
|
|
|
|
_logger.LogInformation("WebSocket connection accepted: {ConnectionId} on node {NodeId}",
|
|
connectionId, _nodeId);
|
|
|
|
return connectionId;
|
|
}
|
|
|
|
public async Task<bool> CloseConnectionAsync(string connectionId)
|
|
{
|
|
var connectionKey = $"{CONNECTION_PREFIX}{connectionId}";
|
|
var userKey = $"{USER_PREFIX}{connectionId}";
|
|
|
|
// 获取连接信息
|
|
var connectionJson = await _distributedCache.GetStringAsync(connectionKey);
|
|
if (connectionJson != null)
|
|
{
|
|
var connection = JsonSerializer.Deserialize<WebSocketConnection>(connectionJson);
|
|
if (connection != null)
|
|
{
|
|
connection.Close();
|
|
await _distributedCache.SetStringAsync(
|
|
connectionKey,
|
|
JsonSerializer.Serialize(connection));
|
|
}
|
|
}
|
|
|
|
// 从节点连接列表中移除
|
|
await RemoveConnectionFromNodeAsync(connectionId);
|
|
|
|
// 清理缓存
|
|
await _distributedCache.RemoveAsync(connectionKey);
|
|
await _distributedCache.RemoveAsync(userKey);
|
|
|
|
_logger.LogInformation("WebSocket connection closed: {ConnectionId}", connectionId);
|
|
return true;
|
|
}
|
|
|
|
public async Task<bool> SendMessageAsync(string connectionId, byte[] message)
|
|
{
|
|
var connectionKey = $"{CONNECTION_PREFIX}{connectionId}";
|
|
var connectionJson = await _distributedCache.GetStringAsync(connectionKey);
|
|
|
|
if (connectionJson != null)
|
|
{
|
|
var connection = JsonSerializer.Deserialize<WebSocketConnection>(connectionJson);
|
|
if (connection?.State == WebSocketState.Open)
|
|
{
|
|
// 这里需要实现消息发送逻辑
|
|
// 可能需要使用消息队列或其他机制
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public async Task<bool> BroadcastMessageAsync(byte[] message)
|
|
{
|
|
// 获取所有节点的连接列表
|
|
var nodes = await GetAllNodesAsync();
|
|
foreach (var node in nodes)
|
|
{
|
|
// 向每个节点发送广播消息
|
|
// 这里需要实现节点间的消息传递机制
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public async Task<bool> SendMessageToUserAsync(string userId, byte[] message)
|
|
{
|
|
// 获取用户的所有连接
|
|
var connections = await GetUserConnectionsAsync(userId);
|
|
foreach (var connection in connections)
|
|
{
|
|
await SendMessageAsync(connection.ConnectionId, message);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public async Task AssociateUserAsync(string connectionId, string userId)
|
|
{
|
|
var connectionKey = $"{CONNECTION_PREFIX}{connectionId}";
|
|
var userKey = $"{USER_PREFIX}{connectionId}";
|
|
|
|
var connectionJson = await _distributedCache.GetStringAsync(connectionKey);
|
|
if (connectionJson != null)
|
|
{
|
|
var connection = JsonSerializer.Deserialize<WebSocketConnection>(connectionJson);
|
|
if (connection != null)
|
|
{
|
|
connection.AssociateUser(userId);
|
|
await _distributedCache.SetStringAsync(
|
|
connectionKey,
|
|
JsonSerializer.Serialize(connection));
|
|
await _distributedCache.SetStringAsync(userKey, userId);
|
|
}
|
|
}
|
|
}
|
|
|
|
public async Task<WebSocketConnection?> GetConnectionAsync(string connectionId)
|
|
{
|
|
var connectionKey = $"{CONNECTION_PREFIX}{connectionId}";
|
|
var connectionJson = await _distributedCache.GetStringAsync(connectionKey);
|
|
return connectionJson != null
|
|
? JsonSerializer.Deserialize<WebSocketConnection>(connectionJson)
|
|
: null;
|
|
}
|
|
|
|
public async Task<IEnumerable<WebSocketConnection>> GetUserConnectionsAsync(string userId)
|
|
{
|
|
var connections = new List<WebSocketConnection>();
|
|
// 这里需要实现获取用户所有连接的逻辑
|
|
return connections;
|
|
}
|
|
|
|
private async Task AddConnectionToNodeAsync(string connectionId)
|
|
{
|
|
var nodeKey = $"{NODE_PREFIX}{_nodeId}";
|
|
var connections = await GetNodeConnectionsAsync();
|
|
connections.Add(connectionId);
|
|
await _distributedCache.SetStringAsync(
|
|
nodeKey,
|
|
JsonSerializer.Serialize(connections));
|
|
}
|
|
|
|
private async Task RemoveConnectionFromNodeAsync(string connectionId)
|
|
{
|
|
var nodeKey = $"{NODE_PREFIX}{_nodeId}";
|
|
var connections = await GetNodeConnectionsAsync();
|
|
connections.Remove(connectionId);
|
|
await _distributedCache.SetStringAsync(
|
|
nodeKey,
|
|
JsonSerializer.Serialize(connections));
|
|
}
|
|
|
|
private async Task<List<string>> GetNodeConnectionsAsync()
|
|
{
|
|
var nodeKey = $"{NODE_PREFIX}{_nodeId}";
|
|
var connectionsJson = await _distributedCache.GetStringAsync(nodeKey);
|
|
return connectionsJson != null
|
|
? JsonSerializer.Deserialize<List<string>>(connectionsJson) ?? new List<string>()
|
|
: new List<string>();
|
|
}
|
|
|
|
private async Task<List<string>> GetAllNodesAsync()
|
|
{
|
|
// 这里需要实现获取所有节点的逻辑
|
|
// 可能需要使用服务发现或其他机制
|
|
return new List<string>();
|
|
}
|
|
}
|