diff --git a/SweetChatService/Handlers/WebSocketMessageHandler.cs b/SweetChatService/Handlers/WsMsgHandler.cs similarity index 72% rename from SweetChatService/Handlers/WebSocketMessageHandler.cs rename to SweetChatService/Handlers/WsMsgHandler.cs index 3dfe0f9..de95cad 100644 --- a/SweetChatService/Handlers/WebSocketMessageHandler.cs +++ b/SweetChatService/Handlers/WsMsgHandler.cs @@ -13,13 +13,13 @@ using System.Threading.Tasks; namespace SweetChatService.Handlers { - internal class WebSocketMessageHandler(ILogger logger, - WebSocketSessionManager sessionManager, - UserService userService) + internal class WsMsgHandler(ILogger logger, + WsSessionManager sessionManager, + PrivateChatService privateChatService) { - private readonly ILogger _logger = logger; - private readonly WebSocketSessionManager _sessionManager = sessionManager; - private readonly UserService _userService = userService; + private readonly ILogger _logger = logger; + private readonly WsSessionManager _sessionManager = sessionManager; + private readonly PrivateChatService _privateChatService = privateChatService; public async ValueTask HandleAsync(WebSocketSession session, WebSocketPackage package) { @@ -55,20 +55,17 @@ namespace SweetChatService.Handlers { switch (msg.Type) { - case ImMessageType.CHAT: - if (_sessionManager.TryGet(msg.To, out var toSession)) - { - await toSession.SendAsync(msg.Content); - } + case ImMessageType.CHAT_PRIVATE: + await _privateChatService.HandleAsync(msg); break; case ImMessageType.ONLINE: _sessionManager.Add(msg.From, session); - await session.SendAsync("ok"); + await session.SendAsync(ImMessage.SystemMessage(msg.From, "OK").ToJson()); break; case ImMessageType.HEARTBEAT: - await session.SendAsync("ok"); + await session.SendAsync(ImMessage.SystemMessage(msg.From, "OK").ToJson()); break; } } diff --git a/SweetChatService/Handlers/WebSocketSessionManager.cs b/SweetChatService/Handlers/WsSessionManager.cs similarity index 63% rename from SweetChatService/Handlers/WebSocketSessionManager.cs rename to SweetChatService/Handlers/WsSessionManager.cs index 07e03e0..633a74f 100644 --- a/SweetChatService/Handlers/WebSocketSessionManager.cs +++ b/SweetChatService/Handlers/WsSessionManager.cs @@ -3,7 +3,7 @@ using System.Collections.Concurrent; namespace SweetChatService.Handlers { - internal class WebSocketSessionManager + internal class WsSessionManager { private readonly ConcurrentDictionary _sessions = new(); @@ -17,6 +17,19 @@ namespace SweetChatService.Handlers _sessions.TryRemove(userId, out _); } + public void RemoveBySession(string sessionId) + { + var keys = _sessions + .Where(x => ReferenceEquals(x.Value.SessionID, sessionId)) + .Select(x => x.Key) + .ToList(); + + foreach (var key in keys) + { + _sessions.TryRemove(key, out _); + } + } + public bool TryGet(string userId, out WebSocketSession? session) { return _sessions.TryGetValue(userId, out session); diff --git a/SweetChatService/Models/ImMessage.cs b/SweetChatService/Models/ImMessage.cs index ec334cc..4c3814c 100644 --- a/SweetChatService/Models/ImMessage.cs +++ b/SweetChatService/Models/ImMessage.cs @@ -1,4 +1,5 @@ -using System.Text.Json.Serialization; +using System.Text.Json; +using System.Text.Json.Serialization; namespace SweetChatService.Models { @@ -15,5 +16,28 @@ namespace SweetChatService.Models [JsonPropertyName("content")] public string Content { get; set; } = default!; + + public static ImMessage SystemMessage(string to, string content) + { + return new ImMessage + { + Type = ImMessageType.SYSTEM, + From = "SYSTEM", + To = to, + Content = content + }; + } + + /// + /// 转为 JSON 字符串 + /// + public string ToJson() + { + return JsonSerializer.Serialize(this, new JsonSerializerOptions + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull + }); + } } } diff --git a/SweetChatService/Models/ImMessageType.cs b/SweetChatService/Models/ImMessageType.cs index 4d8b959..c4691de 100644 --- a/SweetChatService/Models/ImMessageType.cs +++ b/SweetChatService/Models/ImMessageType.cs @@ -5,7 +5,8 @@ namespace SweetChatService.Models [JsonConverter(typeof(JsonStringEnumConverter))] internal enum ImMessageType { - CHAT, + CHAT_PRIVATE, + CHAT_GROUP, ONLINE, HEARTBEAT, SYSTEM, diff --git a/SweetChatService/Program.cs b/SweetChatService/Program.cs index 82e1cb8..2460cad 100644 --- a/SweetChatService/Program.cs +++ b/SweetChatService/Program.cs @@ -12,8 +12,10 @@ var host = Host.CreateDefaultBuilder(args) }) .ConfigureServices((context, services) => { - services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + + services.AddSingleton(); services.AddSingleton(FreeSqlSetup.CreateFreeSql(context.Configuration["ConnectionStrings:Default"])); services.AddSingleton(); @@ -22,18 +24,20 @@ var host = Host.CreateDefaultBuilder(args) .AddWebSocketServer(builder => { builder - //.UseSessionHandler(async (session) => - //{ - // Console.WriteLine($"Client connected: {session.SessionID}"); - //}, - //async (session, error) => - //{ - // Console.WriteLine($"Client disconnected: {session.SessionID}"); - //}) + .UseSessionHandler(async (session) => + { + + }, + async (session, error) => + { + using var scope = session.Server.ServiceProvider.CreateScope(); + var manager = scope.ServiceProvider.GetRequiredService(); + manager.RemoveBySession(session.SessionID); + }) .UseWebSocketMessageHandler(async (session, package) => { using var scope = session.Server.ServiceProvider.CreateScope(); - var handler = scope.ServiceProvider.GetRequiredService(); + var handler = scope.ServiceProvider.GetRequiredService(); await handler.HandleAsync(session, package); }) diff --git a/SweetChatService/Services/PrivateChatService.cs b/SweetChatService/Services/PrivateChatService.cs new file mode 100644 index 0000000..a78ee10 --- /dev/null +++ b/SweetChatService/Services/PrivateChatService.cs @@ -0,0 +1,26 @@ +using SweetChatService.Handlers; +using SweetChatService.Models; + +namespace SweetChatService.Services +{ + internal class PrivateChatService(WsSessionManager wsSessionManager) + { + private readonly WsSessionManager _wsSessionManager = wsSessionManager; + + public async Task HandleAsync(ImMessage msg) + { + // 推送给对方 + if (_wsSessionManager.TryGet(msg.To, out var toSession)) + { + await toSession.SendAsync(msg.ToJson()); + } + + + // 推送给自己 + if (_wsSessionManager.TryGet(msg.From, out var fromSession)) + { + await fromSession.SendAsync(msg.ToJson()); + } + } + } +} diff --git a/SweetChatService/appsettings.json b/SweetChatService/appsettings.json index 011ef2f..38e2d10 100644 --- a/SweetChatService/appsettings.json +++ b/SweetChatService/appsettings.json @@ -1,6 +1,6 @@ { "ConnectionStrings": { - "Default": "Server=localhost;Port=3306;Database=sweet_chat;Uid=root;Pwd=123456;Charset=utf8mb4;" + "Default": "Server=localhost;Port=3306;Database=sweet_chat;Uid=root;Pwd=estun@medical;Charset=utf8mb4;" }, "serverOptions": { "WebSocketServer": {