添加项目文件。
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
using JNPF.WebSockets;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Microsoft.AspNetCore.Builder;
|
||||
|
||||
/// <summary>
|
||||
/// WebSocket 中间件拓展.
|
||||
/// </summary>
|
||||
public static class WebSocketApplicationBuilderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 映射 WebSocket 管理.
|
||||
/// </summary>
|
||||
/// <param name="app"></param>
|
||||
/// <param name="path"></param>
|
||||
/// <param name="handler"></param>
|
||||
/// <returns></returns>
|
||||
public static IApplicationBuilder MapWebSocketManager(
|
||||
this IApplicationBuilder app,
|
||||
PathString path,
|
||||
WebSocketHandler handler)
|
||||
{
|
||||
return app.Map(path, (_app) => _app.UseMiddleware<WebSocketMiddleware>(handler));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using JNPF.WebSockets;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
/// <summary>
|
||||
/// WebSocket服务集合拓展.
|
||||
/// </summary>
|
||||
public static class WebSocketServiceCollectionExtensions
|
||||
{
|
||||
public static IServiceCollection AddWebSocketManager(this IServiceCollection services)
|
||||
{
|
||||
services.AddTransient<WebSocketConnectionManager>();
|
||||
|
||||
var types = AppDomain.CurrentDomain.GetAssemblies()
|
||||
.SelectMany(a => a.GetTypes().Where(t => t.BaseType == typeof(WebSocketHandler)))
|
||||
.ToArray();
|
||||
|
||||
foreach (var type in types)
|
||||
{
|
||||
services.AddSingleton(type);
|
||||
}
|
||||
|
||||
return services;
|
||||
}
|
||||
}
|
||||
223
common/Tnb.WebSockets/Handlers/WebSocketHandler.cs
Normal file
223
common/Tnb.WebSockets/Handlers/WebSocketHandler.cs
Normal file
@@ -0,0 +1,223 @@
|
||||
using System.Net.WebSockets;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using JNPF.Extras.WebSockets.Models;
|
||||
namespace JNPF.WebSockets;
|
||||
|
||||
/// <summary>
|
||||
/// WebSocket 处理程序.
|
||||
/// </summary>
|
||||
public abstract class WebSocketHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// WebSocket 连接管理.
|
||||
/// </summary>
|
||||
protected WebSocketConnectionManager WebSocketConnectionManager { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 初始化一个<see cref="WebSocketHandler"/>类型的新实例.
|
||||
/// </summary>
|
||||
public WebSocketHandler(WebSocketConnectionManager webSocketConnectionManager)
|
||||
{
|
||||
WebSocketConnectionManager = webSocketConnectionManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 连接.
|
||||
/// </summary>
|
||||
/// <param name="socket">socket.</param>
|
||||
/// <returns></returns>
|
||||
public virtual async Task OnConnected(WebSocketClient socket)
|
||||
{
|
||||
WebSocketConnectionManager.AddSocket(socket);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 连接.
|
||||
/// </summary>
|
||||
/// <param name="socketId">连接ID.</param>
|
||||
/// <param name="socket">socket.</param>
|
||||
/// <returns></returns>
|
||||
public virtual async Task OnConnected(string socketId, WebSocketClient socket)
|
||||
{
|
||||
WebSocketConnectionManager.AddSocket(socketId, socket);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 断开连接.
|
||||
/// </summary>
|
||||
/// <param name="socket"></param>
|
||||
/// <returns></returns>
|
||||
public virtual async Task OnDisconnected(WebSocket socket)
|
||||
{
|
||||
string socketId = WebSocketConnectionManager.GetId(socket);
|
||||
if (!string.IsNullOrWhiteSpace(socketId))
|
||||
await WebSocketConnectionManager.RemoveSocket(socketId).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送消息给指定 id 的 socket.
|
||||
/// </summary>
|
||||
/// <param name="client">socket 客户端.</param>
|
||||
/// <param name="message">消息.</param>
|
||||
/// <returns></returns>
|
||||
public async Task SendMessageAsync(WebSocketClient client, string message)
|
||||
{
|
||||
if (client.WebSocket.State != WebSocketState.Open)
|
||||
return;
|
||||
byte[] encodedMessage = Encoding.UTF8.GetBytes(message);
|
||||
try
|
||||
{
|
||||
await client.WebSocket.SendAsync(
|
||||
buffer: new ArraySegment<byte>(
|
||||
array: encodedMessage,
|
||||
offset: 0,
|
||||
count: encodedMessage.Length),
|
||||
messageType: WebSocketMessageType.Text,
|
||||
endOfMessage: true,
|
||||
cancellationToken: CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
catch (WebSocketException e)
|
||||
{
|
||||
if (e.WebSocketErrorCode == WebSocketError.ConnectionClosedPrematurely)
|
||||
{
|
||||
await OnDisconnected(client.WebSocket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 给指定 socket 发送信息.
|
||||
/// </summary>
|
||||
/// <param name="socketId">连接ID.</param>
|
||||
/// <param name="message">消息内容.</param>
|
||||
/// <returns></returns>
|
||||
public async Task SendMessageAsync(string socketId, string message)
|
||||
{
|
||||
var socket = WebSocketConnectionManager.GetSocketById(socketId);
|
||||
if (socket != null)
|
||||
await SendMessageAsync(socket, message).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送消息 全频道.
|
||||
/// </summary>
|
||||
/// <param name="message">消息内容.</param>
|
||||
/// <returns></returns>
|
||||
public async Task SendMessageToAllAsync(string message)
|
||||
{
|
||||
foreach (var pair in WebSocketConnectionManager.GetAll())
|
||||
{
|
||||
try
|
||||
{
|
||||
if (pair.Value.WebSocket.State == WebSocketState.Open)
|
||||
await SendMessageAsync(pair.Value, message).ConfigureAwait(false);
|
||||
}
|
||||
catch (WebSocketException e)
|
||||
{
|
||||
if (e.WebSocketErrorCode == WebSocketError.ConnectionClosedPrematurely)
|
||||
{
|
||||
await OnDisconnected(pair.Value.WebSocket);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 给指定用户组发送信息.
|
||||
/// </summary>
|
||||
/// <param name="userID">用户ID.</param>
|
||||
/// <param name="message">消息内容.</param>
|
||||
/// <returns></returns>
|
||||
public async Task SendMessageToUserAsync(string userID, string message)
|
||||
{
|
||||
var sockets = WebSocketConnectionManager.GetAllFromUser(userID);
|
||||
if (sockets != null)
|
||||
{
|
||||
foreach (var socket in sockets)
|
||||
{
|
||||
await SendMessageAsync(socket, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 给指定租户组发送信息.
|
||||
/// </summary>
|
||||
/// <param name="tenantID">租户ID.</param>
|
||||
/// <param name="message">消息内容.</param>
|
||||
/// <returns></returns>
|
||||
public async Task SendMessageToTenantAsync(string tenantID, string message)
|
||||
{
|
||||
var sockets = WebSocketConnectionManager.GetAllFromTenant(tenantID);
|
||||
if (sockets != null)
|
||||
{
|
||||
foreach (var socket in sockets)
|
||||
{
|
||||
await SendMessageAsync(socket, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 给指定租户组发送信息.
|
||||
/// </summary>
|
||||
/// <param name="tenantID">租户ID.</param>
|
||||
/// <param name="message">消息内容.</param>
|
||||
/// <param name="except">除了某个用户.</param>
|
||||
/// <returns></returns>
|
||||
public async Task SendMessageToTenantAsync(string tenantID, string message, string except)
|
||||
{
|
||||
var sockets = WebSocketConnectionManager.GetAllFromTenant(tenantID);
|
||||
if (sockets != null)
|
||||
{
|
||||
foreach (var id in sockets)
|
||||
{
|
||||
if (id != except)
|
||||
await SendMessageAsync(id, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取租户组内全部用户ID.
|
||||
/// </summary>
|
||||
/// <param name="tenantID"></param>
|
||||
/// <returns></returns>
|
||||
public List<string> GetAllUserIdFromTenant(string tenantID)
|
||||
{
|
||||
List<string> connectionList = new List<string>();
|
||||
foreach (var item in WebSocketConnectionManager.GetAllFromTenant(tenantID))
|
||||
{
|
||||
var client = WebSocketConnectionManager.GetSocketById(item);
|
||||
if (client != null && !connectionList.Any(it => it.Equals(client.UserId)))
|
||||
connectionList.Add(client.UserId);
|
||||
}
|
||||
|
||||
return connectionList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 接收信息.
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="result"></param>
|
||||
/// <param name="receivedMessage"></param>
|
||||
/// <returns></returns>
|
||||
public virtual async Task ReceiveAsync(WebSocketClient client, WebSocketReceiveResult result, string receivedMessage)
|
||||
{
|
||||
try
|
||||
{
|
||||
await SendMessageAsync(client, receivedMessage).ConfigureAwait(false);
|
||||
}
|
||||
catch (TargetParameterCountException)
|
||||
{
|
||||
await SendMessageAsync(client, JsonSerializer.Serialize(new { method = "error", msg = $"does not take parameters!" })).ConfigureAwait(false);
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
await SendMessageAsync(client, JsonSerializer.Serialize(new { method = "error", msg = $"takes different arguments!" })).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
215
common/Tnb.WebSockets/Manager/WebSocketConnectionManager.cs
Normal file
215
common/Tnb.WebSockets/Manager/WebSocketConnectionManager.cs
Normal file
@@ -0,0 +1,215 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Net.WebSockets;
|
||||
using JNPF.Extras.WebSockets.Models;
|
||||
|
||||
namespace JNPF.WebSockets;
|
||||
|
||||
/// <summary>
|
||||
/// WebSocket 连接管理.
|
||||
/// </summary>
|
||||
public class WebSocketConnectionManager
|
||||
{
|
||||
/// <summary>
|
||||
/// 全部 socket 池.
|
||||
/// </summary>
|
||||
private ConcurrentDictionary<string, WebSocketClient> _sockets = new ConcurrentDictionary<string, WebSocketClient>();
|
||||
|
||||
/// <summary>
|
||||
/// 用户组 socket 池.
|
||||
/// </summary>
|
||||
private ConcurrentDictionary<string, List<string>> _users = new ConcurrentDictionary<string, List<string>>();
|
||||
|
||||
/// <summary>
|
||||
/// 租户组 socket 池.
|
||||
/// </summary>
|
||||
private ConcurrentDictionary<string, List<string>> _tenant = new ConcurrentDictionary<string, List<string>>();
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定 id 的 socket.
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
public WebSocketClient GetSocketById(string id)
|
||||
{
|
||||
if (_sockets.TryGetValue(id, out WebSocketClient socket))
|
||||
return socket;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取全部socket.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public ConcurrentDictionary<string, WebSocketClient> GetAll()
|
||||
{
|
||||
return _sockets;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取租户组内全部socket.
|
||||
/// </summary>
|
||||
/// <param name="tenantID"></param>
|
||||
/// <returns></returns>
|
||||
public List<string> GetAllFromTenant(string tenantID)
|
||||
{
|
||||
if (_tenant.ContainsKey(tenantID))
|
||||
{
|
||||
return _tenant[tenantID];
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取用户组内全部socket.
|
||||
/// </summary>
|
||||
/// <param name="userID"></param>
|
||||
/// <returns></returns>
|
||||
public List<string> GetAllFromUser(string userID)
|
||||
{
|
||||
if (_users.ContainsKey(userID))
|
||||
{
|
||||
return _users[userID];
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据 socket 获取其 id.
|
||||
/// </summary>
|
||||
/// <param name="socket"></param>
|
||||
/// <returns></returns>
|
||||
public string GetId(WebSocket socket)
|
||||
{
|
||||
return _sockets.FirstOrDefault(p => p.Value.WebSocket == socket).Key;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加无连接ID socket.
|
||||
/// </summary>
|
||||
/// <param name="socket"></param>
|
||||
public void AddSocket(WebSocketClient socket)
|
||||
{
|
||||
_sockets.TryAdd(CreateConnectionId(), socket);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加带连接 id socket.
|
||||
/// </summary>
|
||||
/// <param name="socketID"></param>
|
||||
/// <param name="socket"></param>
|
||||
public void AddSocket(string socketID, WebSocketClient socket)
|
||||
{
|
||||
_sockets.TryAdd(socketID, socket);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将连接添加至租户组.
|
||||
/// </summary>
|
||||
/// <param name="socketID"></param>
|
||||
/// <param name="tenantID"></param>
|
||||
public void AddToTenant(string socketID, string tenantID)
|
||||
{
|
||||
if (_tenant.ContainsKey(tenantID))
|
||||
{
|
||||
if (!_tenant[tenantID].Contains(socketID)) _tenant[tenantID].Add(socketID);
|
||||
return;
|
||||
}
|
||||
|
||||
_tenant.TryAdd(tenantID, new List<string> { socketID });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移除租户内某个连接.
|
||||
/// </summary>
|
||||
/// <param name="socketID"></param>
|
||||
/// <param name="tenantID"></param>
|
||||
public void RemoveFromTenant(string socketID, string tenantID)
|
||||
{
|
||||
if (_tenant.ContainsKey(tenantID))
|
||||
{
|
||||
_tenant[tenantID].Remove(socketID);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将连接添加至用户组
|
||||
/// 用户可以多端登录.
|
||||
/// </summary>
|
||||
/// <param name="socketID"></param>
|
||||
/// <param name="userID">格式为租户ID+用户ID.</param>
|
||||
public void AddToUser(string socketID, string userID)
|
||||
{
|
||||
if (_users.ContainsKey(userID))
|
||||
{
|
||||
if (!_users[userID].Contains(socketID)) _users[userID].Add(socketID);
|
||||
return;
|
||||
}
|
||||
|
||||
_users.TryAdd(userID, new List<string> { socketID });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移除用户组内某个连接.
|
||||
/// </summary>
|
||||
/// <param name="socketID"></param>
|
||||
/// <param name="userID">格式为租户ID+用户ID.</param>
|
||||
public void RemoveFromUser(string socketID, string userID)
|
||||
{
|
||||
if (_users.ContainsKey(userID))
|
||||
{
|
||||
_users[userID].Remove(socketID);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移除某个 socket.
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
public async Task RemoveSocket(string id)
|
||||
{
|
||||
if (id == null) return;
|
||||
|
||||
if (_sockets.TryRemove(id, out WebSocketClient client))
|
||||
{
|
||||
if (client.WebSocket.State != WebSocketState.Open) return;
|
||||
|
||||
await client.WebSocket.CloseAsync(closeStatus: WebSocketCloseStatus.NormalClosure,
|
||||
statusDescription: "Closed by the WebSocketManager",
|
||||
cancellationToken: CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成连接ID.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private string CreateConnectionId()
|
||||
{
|
||||
return Guid.NewGuid().ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取全部客户端数量.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public int GetSocketClientCount()
|
||||
{
|
||||
return _sockets.Count();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 返回用户组客户端数量.
|
||||
/// </summary>
|
||||
/// <param name="userID"></param>
|
||||
/// <returns></returns>
|
||||
public int GetSocketClientToUserCount(string userID)
|
||||
{
|
||||
if (_users.ContainsKey(userID))
|
||||
return _users[userID].Count();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
140
common/Tnb.WebSockets/Middlewares/WebSocketMiddleware.cs
Normal file
140
common/Tnb.WebSockets/Middlewares/WebSocketMiddleware.cs
Normal file
@@ -0,0 +1,140 @@
|
||||
using System.Net;
|
||||
using System.Net.WebSockets;
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
using JNPF.Common.Net;
|
||||
using JNPF.Common.Security;
|
||||
using JNPF.DataEncryption;
|
||||
using JNPF.Extras.WebSockets.Models;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.IdentityModel.JsonWebTokens;
|
||||
|
||||
namespace JNPF.WebSockets;
|
||||
|
||||
/// <summary>
|
||||
/// WebSocket 中间件.
|
||||
/// </summary>
|
||||
public class WebSocketMiddleware
|
||||
{
|
||||
/// <summary>
|
||||
/// 请求委托.
|
||||
/// </summary>
|
||||
private readonly RequestDelegate _next;
|
||||
|
||||
/// <summary>
|
||||
/// webSocket 处理程序.
|
||||
/// </summary>
|
||||
private WebSocketHandler _webSocketHandler { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 初始化一个<see cref="WebSocketMiddleware"/>类型的新实例.
|
||||
/// </summary>
|
||||
/// <param name="next"></param>
|
||||
/// <param name="webSocketHandler"></param>
|
||||
public WebSocketMiddleware(
|
||||
RequestDelegate next,
|
||||
WebSocketHandler webSocketHandler)
|
||||
{
|
||||
_next = next;
|
||||
_webSocketHandler = webSocketHandler;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步调用.
|
||||
/// </summary>
|
||||
public async Task InvokeAsync(HttpContext context)
|
||||
{
|
||||
if (!context.WebSockets.IsWebSocketRequest)
|
||||
{
|
||||
await _next.Invoke(context);
|
||||
return;
|
||||
}
|
||||
|
||||
WebSocket? socket = await context.WebSockets.AcceptWebSocketAsync().ConfigureAwait(false);
|
||||
|
||||
var token = new JsonWebToken(context.Request.Path.ToString().TrimStart('/').Replace("Bearer%20", string.Empty).Replace("bearer%20", string.Empty));
|
||||
var httpContext = (DefaultHttpContext)context;
|
||||
httpContext.Request.Headers["Authorization"] = HttpUtility.UrlDecode(context.Request.Path.ToString().TrimStart('/'), Encoding.UTF8);
|
||||
UserAgent userAgent = new UserAgent(httpContext);
|
||||
if (!JWTEncryption.ValidateJwtBearerToken(httpContext, out token))
|
||||
{
|
||||
await _webSocketHandler.OnDisconnected(socket);
|
||||
}
|
||||
else
|
||||
{
|
||||
var connectionId = Guid.NewGuid().ToString("N");
|
||||
var wsClient = new WebSocketClient
|
||||
{
|
||||
ConnectionId = connectionId,
|
||||
WebSocket = socket,
|
||||
LoginIpAddress = NetHelper.Ip,
|
||||
LoginPlatForm = string.Format("{0}-{1}", userAgent.OS.ToString(), userAgent.RawValue)
|
||||
};
|
||||
|
||||
await _webSocketHandler.OnConnected(connectionId, wsClient).ConfigureAwait(false);
|
||||
|
||||
await Receive(wsClient, async (result, serializedMessage) =>
|
||||
{
|
||||
switch (result.MessageType)
|
||||
{
|
||||
case WebSocketMessageType.Text:
|
||||
await _webSocketHandler.ReceiveAsync(wsClient, result, serializedMessage).ConfigureAwait(false);
|
||||
break;
|
||||
case WebSocketMessageType.Close:
|
||||
await _webSocketHandler.OnDisconnected(socket);
|
||||
break;
|
||||
case WebSocketMessageType.Binary:
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 接收数据.
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="handleMessage"></param>
|
||||
/// <returns></returns>
|
||||
private async Task Receive(WebSocketClient client, Action<WebSocketReceiveResult, string> handleMessage)
|
||||
{
|
||||
while (client.WebSocket.State == WebSocketState.Open)
|
||||
{
|
||||
ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[1024 * 4]);
|
||||
string message = string.Empty;
|
||||
WebSocketReceiveResult result = null;
|
||||
try
|
||||
{
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
do
|
||||
{
|
||||
result = await client.WebSocket.ReceiveAsync(buffer, CancellationToken.None);
|
||||
ms.Write(buffer.Array, buffer.Offset, result.Count);
|
||||
}
|
||||
while (!result.EndOfMessage);
|
||||
|
||||
ms.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
using (var reader = new StreamReader(ms, Encoding.UTF8))
|
||||
{
|
||||
message = await reader.ReadToEndAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
handleMessage(result, message);
|
||||
}
|
||||
catch (WebSocketException e)
|
||||
{
|
||||
if (e.WebSocketErrorCode == WebSocketError.ConnectionClosedPrematurely)
|
||||
{
|
||||
client.WebSocket.Abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await _webSocketHandler.OnDisconnected(client.WebSocket);
|
||||
}
|
||||
}
|
||||
76
common/Tnb.WebSockets/Models/WebSocketClient.cs
Normal file
76
common/Tnb.WebSockets/Models/WebSocketClient.cs
Normal file
@@ -0,0 +1,76 @@
|
||||
using System.Net.WebSockets;
|
||||
using JNPF.Common.Enums;
|
||||
using SqlSugar;
|
||||
|
||||
namespace JNPF.Extras.WebSockets.Models;
|
||||
|
||||
/// <summary>
|
||||
/// WebSocket客户端信息.
|
||||
/// </summary>
|
||||
public class WebSocketClient
|
||||
{
|
||||
/// <summary>
|
||||
/// 连接Id.
|
||||
/// </summary>
|
||||
public string ConnectionId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户Id.
|
||||
/// </summary>
|
||||
public string UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户账号.
|
||||
/// </summary>
|
||||
public string Account { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 头像.
|
||||
/// </summary>
|
||||
public string HeadIcon { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户名称.
|
||||
/// </summary>
|
||||
public string UserName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 登录IP.
|
||||
/// </summary>
|
||||
public string LoginIpAddress { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 登录设备.
|
||||
/// </summary>
|
||||
public string LoginPlatForm { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 登录时间.
|
||||
/// </summary>
|
||||
public string LoginTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 连接字符串.
|
||||
/// </summary>
|
||||
public ConnectionConfigOptions ConnectionConfig { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 移动端.
|
||||
/// </summary>
|
||||
public bool IsMobileDevice { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 单一登录方式(1:后登录踢出先登录 2:同时登录).
|
||||
/// </summary>
|
||||
public LoginMethod SingleLogin { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// token.
|
||||
/// </summary>
|
||||
public string Token { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// WebSocket对象.
|
||||
/// </summary>
|
||||
public WebSocket WebSocket { get; set; }
|
||||
}
|
||||
20
common/Tnb.WebSockets/Tnb.WebSockets.csproj
Normal file
20
common/Tnb.WebSockets/Tnb.WebSockets.csproj
Normal file
@@ -0,0 +1,20 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="$(SolutionDir)\common.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Description>JNPF WebSocket 拓展插件。</Description>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<GenerateDocumentationFile>False</GenerateDocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.WebSockets" Version="2.2.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Tnb.Common\Tnb.Common.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
Reference in New Issue
Block a user