feat:初始化工程
This commit is contained in:
203
.gitignore
vendored
Normal file
203
.gitignore
vendored
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
|
## files generated by popular Visual Studio add-ons.
|
||||||
|
|
||||||
|
# User-specific files
|
||||||
|
*.rsuser
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.userosscache
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||||
|
*.userprefs
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
[Dd]ebug/
|
||||||
|
[Dd]ebugPublic/
|
||||||
|
[Rr]elease/
|
||||||
|
[Rr]eleases/
|
||||||
|
x64/
|
||||||
|
x86/
|
||||||
|
[Ww][Ii][Nn]32/
|
||||||
|
[Aa][Rr][Mm]/
|
||||||
|
[Aa][Rr][Mm]64/
|
||||||
|
bld/
|
||||||
|
[Bb]in/
|
||||||
|
[Oo]bj/
|
||||||
|
[Ll]og/
|
||||||
|
|
||||||
|
# Visual Studio 2015/2017/2019/2022 cache/options directory
|
||||||
|
.vs/
|
||||||
|
|
||||||
|
# MSTest test Results
|
||||||
|
[Tt]est[Rr]esult*/
|
||||||
|
[Bb]uild[Ll]og.*
|
||||||
|
|
||||||
|
# NUnit
|
||||||
|
*.VisualState.xml
|
||||||
|
TestResult.xml
|
||||||
|
nunit-*.xml
|
||||||
|
|
||||||
|
# Build Results of an ATL Project
|
||||||
|
[Dd]ebugPS/
|
||||||
|
[Rr]eleasePS/
|
||||||
|
dlldata.c
|
||||||
|
|
||||||
|
# Benchmark Results
|
||||||
|
BenchmarkDotNet.Artifacts/
|
||||||
|
|
||||||
|
# .NET Core
|
||||||
|
project.lock.json
|
||||||
|
project.fragment.lock.json
|
||||||
|
artifacts/
|
||||||
|
|
||||||
|
# ASP.NET Scaffolding
|
||||||
|
ScaffoldingReadMe.txt
|
||||||
|
|
||||||
|
# StyleCop
|
||||||
|
StyleCopReport.xml
|
||||||
|
|
||||||
|
# Files built by Visual Studio
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*_h.h
|
||||||
|
*.ilk
|
||||||
|
*.meta
|
||||||
|
*.obj
|
||||||
|
*.iobj
|
||||||
|
*.pch
|
||||||
|
*.pdb
|
||||||
|
*.ipdb
|
||||||
|
*.pgc
|
||||||
|
*.pgd
|
||||||
|
*.rsp
|
||||||
|
*.sbr
|
||||||
|
*.tlb
|
||||||
|
*.tli
|
||||||
|
*.tlh
|
||||||
|
*.tmp
|
||||||
|
*.tmp_proj
|
||||||
|
*_wpftmp.csproj
|
||||||
|
*.log
|
||||||
|
*.tlog
|
||||||
|
*.vspscc
|
||||||
|
*.vssscc
|
||||||
|
.builds
|
||||||
|
*.pidb
|
||||||
|
*.svclog
|
||||||
|
*.scc
|
||||||
|
|
||||||
|
# Chutzpah Test files
|
||||||
|
_Chutzpah*
|
||||||
|
|
||||||
|
# Visual C++ cache files
|
||||||
|
ipch/
|
||||||
|
*.aps
|
||||||
|
*.ncb
|
||||||
|
*.opendb
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
*.cachefile
|
||||||
|
*.VC.db
|
||||||
|
*.VC.VC.opendb
|
||||||
|
|
||||||
|
# Visual Studio profiler
|
||||||
|
*.psess
|
||||||
|
*.vsp
|
||||||
|
*.vspx
|
||||||
|
*.sap
|
||||||
|
|
||||||
|
# Visual Studio Trace Files
|
||||||
|
*.e2e
|
||||||
|
|
||||||
|
# TFS 2012 Local Workspace
|
||||||
|
$tf/
|
||||||
|
|
||||||
|
# Guidance Automation Toolkit
|
||||||
|
*.gpState
|
||||||
|
|
||||||
|
# ReSharper is a .NET coding add-in
|
||||||
|
_ReSharper*/
|
||||||
|
*.[Rr]e[Ss]harper
|
||||||
|
*.DotSettings.user
|
||||||
|
|
||||||
|
# TeamCity is a build add-in
|
||||||
|
_TeamCity*
|
||||||
|
|
||||||
|
# DotCover is a Code Coverage Tool
|
||||||
|
*.dotCover
|
||||||
|
|
||||||
|
# AxoCover is a Code Coverage Tool
|
||||||
|
.axoCover/*
|
||||||
|
!.axoCover/settings.json
|
||||||
|
|
||||||
|
# Coverlet is a free, cross platform Code Coverage Tool
|
||||||
|
coverage*.json
|
||||||
|
coverage*.xml
|
||||||
|
coverage*.info
|
||||||
|
|
||||||
|
# Visual Studio code coverage results
|
||||||
|
*.coverage
|
||||||
|
*.coveragexml
|
||||||
|
|
||||||
|
# NCrunch
|
||||||
|
_NCrunch_*
|
||||||
|
.*crunch*.local.xml
|
||||||
|
nCrunchTemp_*
|
||||||
|
|
||||||
|
# MightyMoose
|
||||||
|
*.mm.*
|
||||||
|
AutoTest.Net/
|
||||||
|
|
||||||
|
# Web workbench (sass)
|
||||||
|
.sass-cache/
|
||||||
|
|
||||||
|
# Installshield output folder
|
||||||
|
[Ee]xpress/
|
||||||
|
|
||||||
|
# DocProject is a documentation generator add-in
|
||||||
|
DocProject/buildhelp/
|
||||||
|
DocProject/Help/*.HxT
|
||||||
|
DocProject/Help/*.HxC
|
||||||
|
DocProject/Help/*.hhc
|
||||||
|
DocProject/Help/*.hhk
|
||||||
|
DocProject/Help/*.hhp
|
||||||
|
DocProject/Help/Html2
|
||||||
|
DocProject/Help/html
|
||||||
|
|
||||||
|
# Click-Once directory
|
||||||
|
publish/
|
||||||
|
|
||||||
|
# Publish Web Output
|
||||||
|
*.[Pp]ublish.xml
|
||||||
|
*.azurePubxml
|
||||||
|
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||||
|
# but database connection strings (with potential passwords) will be unencrypted
|
||||||
|
*.pubxml
|
||||||
|
*.publishproj
|
||||||
|
|
||||||
|
# Microsoft Azure Web App publish settings.
|
||||||
|
PublishScripts/
|
||||||
|
|
||||||
|
# NuGet Packages
|
||||||
|
*.nupkg
|
||||||
|
# The packages folder can be ignored because of Package Restore
|
||||||
|
**/[Pp]ackages/*
|
||||||
|
# except build/, which is used as an MSBuild target.
|
||||||
|
!**/[Pp]ackages/build/
|
||||||
|
# Uncomment if necessary however generally it will be regenerated when needed
|
||||||
|
#!**/[Pp]ackages/repositories.config
|
||||||
|
|
||||||
|
# NuGet Symbol Packages
|
||||||
|
*.snupkg
|
||||||
|
|
||||||
|
# .NET Core SDK
|
||||||
|
project.fragment.lock.json
|
||||||
|
artifacts/
|
||||||
|
|
||||||
|
# Windows Installer files from build outputs
|
||||||
|
*.cab
|
||||||
|
*.msi
|
||||||
|
*.msix
|
||||||
|
*.msm
|
||||||
|
*.msp
|
||||||
25
SweetChatService.sln
Normal file
25
SweetChatService.sln
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.14.36109.1 d17.14
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SweetChatService", "SweetChatService\SweetChatService.csproj", "{9353E5F0-839A-427B-A27E-01207A59A87A}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{9353E5F0-839A-427B-A27E-01207A59A87A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{9353E5F0-839A-427B-A27E-01207A59A87A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{9353E5F0-839A-427B-A27E-01207A59A87A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{9353E5F0-839A-427B-A27E-01207A59A87A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {FDAF22F8-D354-4266-8823-C5457E887D4C}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
19
SweetChatService/Config/FreeSqlSetup.cs
Normal file
19
SweetChatService/Config/FreeSqlSetup.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
using FreeSql;
|
||||||
|
|
||||||
|
namespace SweetChatService.Config
|
||||||
|
{
|
||||||
|
public class FreeSqlSetup
|
||||||
|
{
|
||||||
|
public static IFreeSql CreateFreeSql(string connectionString)
|
||||||
|
{
|
||||||
|
return new FreeSqlBuilder()
|
||||||
|
.UseConnectionString(DataType.MySql, connectionString)
|
||||||
|
.UseAutoSyncStructure(false)
|
||||||
|
.UseMonitorCommand(cmd =>
|
||||||
|
{
|
||||||
|
Console.WriteLine(cmd.CommandText);
|
||||||
|
})
|
||||||
|
.Build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
21
SweetChatService/Config/Startup.cs
Normal file
21
SweetChatService/Config/Startup.cs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
namespace SweetChatService.Config
|
||||||
|
{
|
||||||
|
public class Startup
|
||||||
|
{
|
||||||
|
public void ConfigureServices(IServiceCollection services)
|
||||||
|
{
|
||||||
|
services.AddControllers();
|
||||||
|
services.AddEndpointsApiExplorer();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
||||||
|
{
|
||||||
|
app.UseRouting();
|
||||||
|
|
||||||
|
app.UseEndpoints(endpoints =>
|
||||||
|
{
|
||||||
|
endpoints.MapControllers();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
39
SweetChatService/Controllers/AuthController.cs
Normal file
39
SweetChatService/Controllers/AuthController.cs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using SweetChatService.Dto;
|
||||||
|
using SweetChatService.Services;
|
||||||
|
|
||||||
|
namespace SweetChatService.Controllers
|
||||||
|
{
|
||||||
|
[ApiController]
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
public class AuthController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly UserService _userService;
|
||||||
|
|
||||||
|
public AuthController(UserService userService)
|
||||||
|
{
|
||||||
|
_userService = userService;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("login")]
|
||||||
|
public IActionResult Login([FromBody] LoginDto dto)
|
||||||
|
{
|
||||||
|
var user = _userService.QueryUserByName(dto.UserName);
|
||||||
|
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
return Unauthorized(new
|
||||||
|
{
|
||||||
|
message = "用户名不存在"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Ok(new
|
||||||
|
{
|
||||||
|
userId = user.Id
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
4
SweetChatService/Dto/LoginDto.cs
Normal file
4
SweetChatService/Dto/LoginDto.cs
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
namespace SweetChatService.Dto
|
||||||
|
{
|
||||||
|
public record LoginDto(string UserName, string Password);
|
||||||
|
}
|
||||||
29
SweetChatService/Entity/User.cs
Normal file
29
SweetChatService/Entity/User.cs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
using FreeSql.DataAnnotations;
|
||||||
|
|
||||||
|
namespace SweetChatService.Entity
|
||||||
|
{
|
||||||
|
[Table(Name = "user")]
|
||||||
|
public class User
|
||||||
|
{
|
||||||
|
[Column(Name = "id", IsPrimary = true, IsIdentity = true)]
|
||||||
|
public long Id { get; set; }
|
||||||
|
|
||||||
|
[Column(Name = "phone", StringLength = 20)]
|
||||||
|
public string Phone { get; set; } = "";
|
||||||
|
|
||||||
|
[Column(Name = "nickname", StringLength = 50)]
|
||||||
|
public string Nickname { get; set; } = "";
|
||||||
|
|
||||||
|
[Column(Name = "avatar_url", StringLength = 255)]
|
||||||
|
public string AvatarUrl { get; set; } = "";
|
||||||
|
|
||||||
|
[Column(Name = "gender")]
|
||||||
|
public byte Gender { get; set; } = 0;
|
||||||
|
|
||||||
|
[Column(Name = "create_time", ServerTime = DateTimeKind.Local, CanUpdate = false)]
|
||||||
|
public DateTime CreateTime { get; set; }
|
||||||
|
|
||||||
|
[Column(Name = "update_time", ServerTime = DateTimeKind.Local)]
|
||||||
|
public DateTime UpdateTime { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
76
SweetChatService/Handlers/WebSocketMessageHandler.cs
Normal file
76
SweetChatService/Handlers/WebSocketMessageHandler.cs
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
using Microsoft.AspNetCore.WebUtilities;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using SuperSocket.WebSocket;
|
||||||
|
using SuperSocket.WebSocket.Server;
|
||||||
|
using SweetChatService.Models;
|
||||||
|
using SweetChatService.Services;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace SweetChatService.Handlers
|
||||||
|
{
|
||||||
|
internal class WebSocketMessageHandler(ILogger<WebSocketMessageHandler> logger,
|
||||||
|
WebSocketSessionManager sessionManager,
|
||||||
|
UserService userService)
|
||||||
|
{
|
||||||
|
private readonly ILogger<WebSocketMessageHandler> _logger = logger;
|
||||||
|
private readonly WebSocketSessionManager _sessionManager = sessionManager;
|
||||||
|
private readonly UserService _userService = userService;
|
||||||
|
|
||||||
|
public async ValueTask HandleAsync(WebSocketSession session, WebSocketPackage package)
|
||||||
|
{
|
||||||
|
var query = QueryHelpers.ParseQuery(session.Path.TrimStart('/'));
|
||||||
|
|
||||||
|
// 1. 判断url是否正确
|
||||||
|
if (!query.TryGetValue("userId", out var userId))
|
||||||
|
{
|
||||||
|
_logger.LogWarning("未知连接");
|
||||||
|
await session.CloseAsync();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 判断userId是否存在
|
||||||
|
_logger.LogInformation($"[userId] {userId}");
|
||||||
|
// _logger.LogInformation($"[WebSocket] {package.Message}");
|
||||||
|
|
||||||
|
// 3. 根据消息类型执行操作
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var message = JsonSerializer.Deserialize<ImMessage>(package.Message);
|
||||||
|
await HandleImMessage(session, message);
|
||||||
|
}
|
||||||
|
catch (JsonException ex)
|
||||||
|
{
|
||||||
|
_logger.LogWarning($"未知消息: {ex.Message}");
|
||||||
|
await session.CloseAsync();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task HandleImMessage(WebSocketSession session, ImMessage msg)
|
||||||
|
{
|
||||||
|
switch (msg.Type)
|
||||||
|
{
|
||||||
|
case ImMessageType.CHAT:
|
||||||
|
if (_sessionManager.TryGet(msg.To, out var toSession))
|
||||||
|
{
|
||||||
|
await toSession.SendAsync(msg.Content);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ImMessageType.ONLINE:
|
||||||
|
_sessionManager.Add(msg.From, session);
|
||||||
|
await session.SendAsync("ok");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ImMessageType.HEARTBEAT:
|
||||||
|
await session.SendAsync("ok");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
27
SweetChatService/Handlers/WebSocketSessionManager.cs
Normal file
27
SweetChatService/Handlers/WebSocketSessionManager.cs
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
using SuperSocket.WebSocket.Server;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
|
||||||
|
namespace SweetChatService.Handlers
|
||||||
|
{
|
||||||
|
internal class WebSocketSessionManager
|
||||||
|
{
|
||||||
|
private readonly ConcurrentDictionary<string, WebSocketSession> _sessions = new();
|
||||||
|
|
||||||
|
public void Add(string userId, WebSocketSession session)
|
||||||
|
{
|
||||||
|
_sessions[userId] = session;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Remove(string userId)
|
||||||
|
{
|
||||||
|
_sessions.TryRemove(userId, out _);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGet(string userId, out WebSocketSession? session)
|
||||||
|
{
|
||||||
|
return _sessions.TryGetValue(userId, out session);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<WebSocketSession> All => _sessions.Values;
|
||||||
|
}
|
||||||
|
}
|
||||||
19
SweetChatService/Models/ImMessage.cs
Normal file
19
SweetChatService/Models/ImMessage.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace SweetChatService.Models
|
||||||
|
{
|
||||||
|
internal class ImMessage
|
||||||
|
{
|
||||||
|
[JsonPropertyName("type")]
|
||||||
|
public ImMessageType Type { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("from")]
|
||||||
|
public string From { get; set; } = default!;
|
||||||
|
|
||||||
|
[JsonPropertyName("to")]
|
||||||
|
public string To { get; set; } = default!;
|
||||||
|
|
||||||
|
[JsonPropertyName("content")]
|
||||||
|
public string Content { get; set; } = default!;
|
||||||
|
}
|
||||||
|
}
|
||||||
14
SweetChatService/Models/ImMessageType.cs
Normal file
14
SweetChatService/Models/ImMessageType.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace SweetChatService.Models
|
||||||
|
{
|
||||||
|
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||||||
|
internal enum ImMessageType
|
||||||
|
{
|
||||||
|
CHAT,
|
||||||
|
ONLINE,
|
||||||
|
HEARTBEAT,
|
||||||
|
SYSTEM,
|
||||||
|
NOTICE
|
||||||
|
}
|
||||||
|
}
|
||||||
32
SweetChatService/NLog.config
Normal file
32
SweetChatService/NLog.config
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
autoReload="true">
|
||||||
|
|
||||||
|
<extensions>
|
||||||
|
<add assembly="NLog.Targets.Network" />
|
||||||
|
</extensions>
|
||||||
|
|
||||||
|
<targets async="true">
|
||||||
|
<target name="fluentbit" xsi:type="Network"
|
||||||
|
newLine="true" lineEnding="LF"
|
||||||
|
address="tcp://60.247.145.200:5170">
|
||||||
|
<layout xsi:type="JsonLayout">
|
||||||
|
<attribute name="topic" layout="message-hub"/>
|
||||||
|
<attribute name="timestamp" layout="${longdate:universalTime=true}"/>
|
||||||
|
<attribute name="level" layout="${level:uppercase=true}"/>
|
||||||
|
<attribute name="logger" layout="${logger}"/>
|
||||||
|
<attribute name="message" layout="${message}"/>
|
||||||
|
<attribute name="throwable" layout="${exception:format=ToString}"/>
|
||||||
|
</layout>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="stdout"
|
||||||
|
xsi:type="Console"
|
||||||
|
layout="${longdate} ${level:uppercase=true}: ${logger} - ${message}${onexception:${newline}${exception:format=ToString}}" />
|
||||||
|
</targets>
|
||||||
|
|
||||||
|
<rules>
|
||||||
|
<logger name="*" minlevel="Info" writeTo="stdout"/>
|
||||||
|
</rules>
|
||||||
|
</nlog>
|
||||||
51
SweetChatService/Program.cs
Normal file
51
SweetChatService/Program.cs
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using NLog.Extensions.Hosting;
|
||||||
|
using SuperSocket.Server.Host;
|
||||||
|
using SuperSocket.WebSocket.Server;
|
||||||
|
using SweetChatService.Config;
|
||||||
|
using SweetChatService.Handlers;
|
||||||
|
using SweetChatService.Services;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
var host = Host.CreateDefaultBuilder(args)
|
||||||
|
.ConfigureWebHostDefaults(webBuilder =>
|
||||||
|
{
|
||||||
|
webBuilder.UseStartup<Startup>();
|
||||||
|
})
|
||||||
|
.ConfigureServices((context, services) =>
|
||||||
|
{
|
||||||
|
services.AddSingleton<WebSocketMessageHandler>();
|
||||||
|
services.AddSingleton<WebSocketSessionManager>();
|
||||||
|
|
||||||
|
services.AddSingleton(FreeSqlSetup.CreateFreeSql(context.Configuration["ConnectionStrings:Default"]));
|
||||||
|
services.AddSingleton<UserService>();
|
||||||
|
})
|
||||||
|
.AsMultipleServerHostBuilder()
|
||||||
|
.AddWebSocketServer(builder =>
|
||||||
|
{
|
||||||
|
builder
|
||||||
|
//.UseSessionHandler(async (session) =>
|
||||||
|
//{
|
||||||
|
// Console.WriteLine($"Client connected: {session.SessionID}");
|
||||||
|
//},
|
||||||
|
//async (session, error) =>
|
||||||
|
//{
|
||||||
|
// Console.WriteLine($"Client disconnected: {session.SessionID}");
|
||||||
|
//})
|
||||||
|
.UseWebSocketMessageHandler(async (session, package) =>
|
||||||
|
{
|
||||||
|
using var scope = session.Server.ServiceProvider.CreateScope();
|
||||||
|
var handler = scope.ServiceProvider.GetRequiredService<WebSocketMessageHandler>();
|
||||||
|
|
||||||
|
await handler.HandleAsync(session, package);
|
||||||
|
})
|
||||||
|
.ConfigureServerOptions((ctx, config) => config.GetSection("WebSocketServer"));
|
||||||
|
})
|
||||||
|
.ConfigureLogging(logging => logging.ClearProviders())
|
||||||
|
.UseNLog()
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
await host.RunAsync();
|
||||||
12
SweetChatService/Properties/launchSettings.json
Normal file
12
SweetChatService/Properties/launchSettings.json
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"profiles": {
|
||||||
|
"SweetChatService": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"launchBrowser": false,
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
},
|
||||||
|
"applicationUrl": "https://localhost:2835;http://localhost:2836"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
18
SweetChatService/Services/UserService.cs
Normal file
18
SweetChatService/Services/UserService.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
using SweetChatService.Entity;
|
||||||
|
|
||||||
|
namespace SweetChatService.Services
|
||||||
|
{
|
||||||
|
public class UserService
|
||||||
|
{
|
||||||
|
private readonly IFreeSql _fsql;
|
||||||
|
|
||||||
|
public UserService(IFreeSql fsql) => _fsql = fsql;
|
||||||
|
|
||||||
|
public User QueryUserByName(string username)
|
||||||
|
{
|
||||||
|
return _fsql.Select<User>()
|
||||||
|
.Where(u => u.Nickname == username)
|
||||||
|
.First();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
28
SweetChatService/SweetChatService.csproj
Normal file
28
SweetChatService/SweetChatService.csproj
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="FreeSql.Provider.MySqlConnector" Version="3.5.310" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.WebUtilities" Version="8.0.0" />
|
||||||
|
<PackageReference Include="NLog.Extensions.Hosting" Version="6.1.3" />
|
||||||
|
<PackageReference Include="SuperSocket" Version="2.0.2" />
|
||||||
|
<PackageReference Include="SuperSocket.WebSocket" Version="2.1.0" />
|
||||||
|
<PackageReference Include="SuperSocket.WebSocket.Server" Version="2.1.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Update="appsettings.json">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="NLog.config">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
16
SweetChatService/appsettings.json
Normal file
16
SweetChatService/appsettings.json
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"ConnectionStrings": {
|
||||||
|
"Default": "Server=localhost;Port=3306;Database=sweet_chat;Uid=root;Pwd=estun@medical;Charset=utf8mb4;"
|
||||||
|
},
|
||||||
|
"serverOptions": {
|
||||||
|
"WebSocketServer": {
|
||||||
|
"name": "WebSocket",
|
||||||
|
"listeners": [
|
||||||
|
{
|
||||||
|
"ip": "Any",
|
||||||
|
"port": 5050
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
141
SweetChatService/sweet_chat.sql
Normal file
141
SweetChatService/sweet_chat.sql
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
-- MySQL dump 10.13 Distrib 8.0.27, for Win64 (x86_64)
|
||||||
|
--
|
||||||
|
-- Host: 127.0.0.1 Database: sweet_chat
|
||||||
|
-- ------------------------------------------------------
|
||||||
|
-- Server version 8.0.27
|
||||||
|
|
||||||
|
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||||
|
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
||||||
|
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
|
||||||
|
/*!50503 SET NAMES utf8 */;
|
||||||
|
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
|
||||||
|
/*!40103 SET TIME_ZONE='+00:00' */;
|
||||||
|
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
|
||||||
|
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
|
||||||
|
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
|
||||||
|
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `conversation`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `conversation`;
|
||||||
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
|
/*!50503 SET character_set_client = utf8mb4 */;
|
||||||
|
CREATE TABLE `conversation` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '会话ID',
|
||||||
|
`type` tinyint NOT NULL COMMENT '1单聊 2群聊',
|
||||||
|
`last_msg_id` bigint DEFAULT '0' COMMENT '最后一条消息ID',
|
||||||
|
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
|
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='会话表';
|
||||||
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `conversation`
|
||||||
|
--
|
||||||
|
|
||||||
|
LOCK TABLES `conversation` WRITE;
|
||||||
|
/*!40000 ALTER TABLE `conversation` DISABLE KEYS */;
|
||||||
|
INSERT INTO `conversation` VALUES (1,1,2,'2026-06-17 13:45:29','2026-06-17 13:50:21');
|
||||||
|
/*!40000 ALTER TABLE `conversation` ENABLE KEYS */;
|
||||||
|
UNLOCK TABLES;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `conversation_member`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `conversation_member`;
|
||||||
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
|
/*!50503 SET character_set_client = utf8mb4 */;
|
||||||
|
CREATE TABLE `conversation_member` (
|
||||||
|
`conversation_id` bigint NOT NULL COMMENT '会话ID',
|
||||||
|
`user_id` bigint NOT NULL COMMENT '用户ID',
|
||||||
|
`unread_count` int DEFAULT '0' COMMENT '未读消息数',
|
||||||
|
`last_read_msg_id` bigint DEFAULT '0' COMMENT '已读到最后一条消息ID',
|
||||||
|
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
|
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (`conversation_id`,`user_id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='会话成员表';
|
||||||
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `conversation_member`
|
||||||
|
--
|
||||||
|
|
||||||
|
LOCK TABLES `conversation_member` WRITE;
|
||||||
|
/*!40000 ALTER TABLE `conversation_member` DISABLE KEYS */;
|
||||||
|
INSERT INTO `conversation_member` VALUES (1,1,1,0,'2026-06-17 13:46:18','2026-06-17 13:50:36'),(1,2,1,0,'2026-06-17 13:46:18','2026-06-17 13:47:27');
|
||||||
|
/*!40000 ALTER TABLE `conversation_member` ENABLE KEYS */;
|
||||||
|
UNLOCK TABLES;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `message`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `message`;
|
||||||
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
|
/*!50503 SET character_set_client = utf8mb4 */;
|
||||||
|
CREATE TABLE `message` (
|
||||||
|
`msg_id` bigint NOT NULL AUTO_INCREMENT COMMENT '消息ID',
|
||||||
|
`conversation_id` bigint NOT NULL COMMENT '会话ID',
|
||||||
|
`sender_id` bigint NOT NULL COMMENT '发送者ID',
|
||||||
|
`content` text NOT NULL COMMENT '消息内容',
|
||||||
|
`msg_type` tinyint DEFAULT '1' COMMENT '1文本 2图片 3语音',
|
||||||
|
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
|
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (`msg_id`)
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='消息表';
|
||||||
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `message`
|
||||||
|
--
|
||||||
|
|
||||||
|
LOCK TABLES `message` WRITE;
|
||||||
|
/*!40000 ALTER TABLE `message` DISABLE KEYS */;
|
||||||
|
INSERT INTO `message` VALUES (1,1,1,'张三,在吗?',1,'2026-06-17 13:46:35','2026-06-17 13:46:35'),(2,1,2,'在,咋了?',1,'2026-06-17 13:49:48','2026-06-17 13:49:48');
|
||||||
|
/*!40000 ALTER TABLE `message` ENABLE KEYS */;
|
||||||
|
UNLOCK TABLES;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `user`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `user`;
|
||||||
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
|
/*!50503 SET character_set_client = utf8mb4 */;
|
||||||
|
CREATE TABLE `user` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '用户ID',
|
||||||
|
`phone` varchar(20) NOT NULL COMMENT '手机号',
|
||||||
|
`nickname` varchar(50) NOT NULL COMMENT '昵称',
|
||||||
|
`avatar_url` varchar(255) DEFAULT '' COMMENT '头像',
|
||||||
|
`gender` tinyint DEFAULT '0' COMMENT '0未知 1男 2女',
|
||||||
|
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
|
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `phone` (`phone`)
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户表';
|
||||||
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `user`
|
||||||
|
--
|
||||||
|
|
||||||
|
LOCK TABLES `user` WRITE;
|
||||||
|
/*!40000 ALTER TABLE `user` DISABLE KEYS */;
|
||||||
|
INSERT INTO `user` VALUES (1,'13800000001','Cxx','',1,'2026-06-17 13:42:21','2026-06-17 13:42:21'),(2,'13800000002','Pjm','',1,'2026-06-17 13:42:21','2026-06-17 18:18:16');
|
||||||
|
/*!40000 ALTER TABLE `user` ENABLE KEYS */;
|
||||||
|
UNLOCK TABLES;
|
||||||
|
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
|
||||||
|
|
||||||
|
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
|
||||||
|
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
|
||||||
|
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
|
||||||
|
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
||||||
|
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
|
||||||
|
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||||
|
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
||||||
|
|
||||||
|
-- Dump completed on 2026-06-17 19:53:25
|
||||||
Reference in New Issue
Block a user