feat:初始化工程

This commit is contained in:
2026-06-17 19:56:40 +08:00
commit 7554523f8d
18 changed files with 774 additions and 0 deletions

203
.gitignore vendored Normal file
View 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
View 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

View 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();
}
}
}

View 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();
});
}
}
}

View 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
});
}
}
}
}

View File

@@ -0,0 +1,4 @@
namespace SweetChatService.Dto
{
public record LoginDto(string UserName, string Password);
}

View 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; }
}
}

View 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;
}
}
}
}

View 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;
}
}

View 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!;
}
}

View File

@@ -0,0 +1,14 @@
using System.Text.Json.Serialization;
namespace SweetChatService.Models
{
[JsonConverter(typeof(JsonStringEnumConverter))]
internal enum ImMessageType
{
CHAT,
ONLINE,
HEARTBEAT,
SYSTEM,
NOTICE
}
}

View 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>

View 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();

View File

@@ -0,0 +1,12 @@
{
"profiles": {
"SweetChatService": {
"commandName": "Project",
"launchBrowser": false,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:2835;http://localhost:2836"
}
}
}

View 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();
}
}
}

View 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>

View 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
}
]
}
}
}

View 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