diff --git a/DbQueryApp/DbQueryApp.csproj b/DbQueryApp/DbQueryApp.csproj index 44fac84807d13635d0b930e3e3d8ed579399964d..3e4aec921cc2cf790fe41f2eae0f8a9f642ffe60 100644 --- a/DbQueryApp/DbQueryApp.csproj +++ b/DbQueryApp/DbQueryApp.csproj @@ -8,7 +8,7 @@ - + - \ No newline at end of file + diff --git a/DbQueryApp/Program.cs b/DbQueryApp/Program.cs index 1c554509cb54d3738255cf7aa789e2a34a6e419b..75d63b971145e8aff4d36ebda9beff5f1ee67277 100644 --- a/DbQueryApp/Program.cs +++ b/DbQueryApp/Program.cs @@ -1,56 +1,95 @@ using System; +using System.Collections.Generic; +using System.Data; using Npgsql; -namespace DbQueryApp +class Program { - class Program + static void Main(string[] args) { - static void Main(string[] args) + // 数据库连接字符串 + string connectionString = "Host=localhost;Port=5432;Database=territory_game;Username=postgres;Password=your_password"; + + try { - try + // 创建连接 + using (NpgsqlConnection connection = new NpgsqlConnection(connectionString)) { - // 数据库连接字符串 - string connectionString = "Host=39.105.7.196;Port=5432;Database=TerritoryGame;Username=postgres;Password=xyq0716"; + connection.Open(); + Console.WriteLine("成功连接到数据库"); - // 创建连接 - using (var connection = new NpgsqlConnection(connectionString)) + // 查询所有房间 + string roomQuery = "SELECT * FROM GameRooms"; + using (NpgsqlCommand roomCommand = new NpgsqlCommand(roomQuery, connection)) { - connection.Open(); - Console.WriteLine("成功连接到数据库"); - - // 查询等待状态的房间 - string query = "SELECT \"Id\", \"Name\", \"CreatedAt\" FROM \"GameRooms\" WHERE \"Status\" = 0"; - using (var command = new NpgsqlCommand(query, connection)) + using (NpgsqlDataReader roomReader = roomCommand.ExecuteReader()) { - using (var reader = command.ExecuteReader()) + Console.WriteLine("\n房间列表:"); + Console.WriteLine("------------------------------------------------------------"); + + while (roomReader.Read()) { - if (!reader.HasRows) - { - Console.WriteLine("没有找到等待状态的房间"); - return; - } - - Console.WriteLine("等待状态的房间列表:"); - Console.WriteLine("----------------------------------------"); - Console.WriteLine("房间ID | 房间名称 | 创建时间"); - Console.WriteLine("----------------------------------------"); - - while (reader.Read()) - { - var id = reader.GetGuid(0); - var name = reader.GetString(1); - var createdAt = reader.GetDateTime(2); - - Console.WriteLine($"{id} | {name} | {createdAt}"); - } + int roomId = roomReader.GetInt32(roomReader.GetOrdinal("Id")); + string roomName = roomReader.GetString(roomReader.GetOrdinal("Name")); + DateTime createdAt = roomReader.GetDateTime(roomReader.GetOrdinal("CreatedAt")); + int status = roomReader.GetInt32(roomReader.GetOrdinal("Status")); + + Console.WriteLine($"房间ID: {roomId}, 名称: {roomName}, 创建时间: {createdAt}, 状态: {status}"); + + // 查询该房间的玩家 + List players = GetRoomPlayers(roomId, connection); + Console.WriteLine($"玩家: {string.Join(", ", players)}"); + + // 查询该房间的观众 + List spectators = GetRoomSpectators(roomId, connection); + Console.WriteLine($"观众: {string.Join(", ", spectators)}"); + Console.WriteLine("------------------------------------------------------------"); } } } } - catch (Exception ex) + } + catch (Exception ex) + { + Console.WriteLine($"发生错误: {ex.Message}"); + } + } + + // 获取房间玩家 + static List GetRoomPlayers(int roomId, NpgsqlConnection connection) + { + List players = new List(); + string query = "SELECT Username FROM Players WHERE GameRoomId = @RoomId"; + using (NpgsqlCommand command = new NpgsqlCommand(query, connection)) + { + command.Parameters.AddWithValue("@RoomId", roomId); + using (NpgsqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + players.Add(reader.GetString(0)); + } + } + } + return players; + } + + // 获取房间观众 + static List GetRoomSpectators(int roomId, NpgsqlConnection connection) + { + List spectators = new List(); + string query = "SELECT Username FROM Spectators WHERE GameRoomId = @RoomId"; + using (NpgsqlCommand command = new NpgsqlCommand(query, connection)) + { + command.Parameters.AddWithValue("@RoomId", roomId); + using (NpgsqlDataReader reader = command.ExecuteReader()) { - Console.WriteLine($"发生错误: {ex.Message}"); + while (reader.Read()) + { + spectators.Add(reader.GetString(0)); + } } } + return spectators; } -} \ No newline at end of file +} diff --git a/DbQueryAppNet8/DbQueryAppNet8.csproj b/DbQueryAppNet8/DbQueryAppNet8.csproj new file mode 100644 index 0000000000000000000000000000000000000000..5d5d01e82ce729d56e9c292fa96e793c2ed7998c --- /dev/null +++ b/DbQueryAppNet8/DbQueryAppNet8.csproj @@ -0,0 +1,14 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + diff --git a/DbQueryAppNet8/Program.cs b/DbQueryAppNet8/Program.cs new file mode 100644 index 0000000000000000000000000000000000000000..efd57d2e992c30c2b8bb7b1e32bd4e2d3c671aa5 --- /dev/null +++ b/DbQueryAppNet8/Program.cs @@ -0,0 +1,186 @@ +using Npgsql; +using System; +using System.Collections.Generic; + +class Program +{ + static void Main() + { + string connectionString = "Host=39.105.7.196;Port=5432;Database=TerritoryGame;Username=postgres;Password=xyq0716;"; + + Console.WriteLine("开始查询表结构..."); + // 首先查询表结构以确定列名 + QueryTableStructure("Players", connectionString); + QueryTableStructure("Spectators", connectionString); + Console.WriteLine("表结构查询完成\n"); + + try + { + using (NpgsqlConnection connection = new NpgsqlConnection(connectionString)) + { + connection.Open(); + Console.WriteLine("数据库连接成功"); + + // 查询所有房间 + string roomQuery = "SELECT * FROM \"GameRooms\" WHERE \"Status\" = 0"; + + using (NpgsqlCommand roomCommand = new NpgsqlCommand(roomQuery, connection)) + using (NpgsqlDataReader roomReader = roomCommand.ExecuteReader()) + { + Console.WriteLine("\n房间列表:"); + Console.WriteLine("----------------------------------------------------------------------------------------------------"); + Console.WriteLine("房间ID | 名称 | 创建时间 | 状态 | 玩家 | 观众"); + Console.WriteLine("----------------------------------------------------------------------------------------------------"); + + while (roomReader.Read()) + { + try + { + Guid id = roomReader.GetGuid(roomReader.GetOrdinal("Id")); + string name = roomReader.GetString(roomReader.GetOrdinal("Name")); + + // 更健壮的时间戳处理 + DateTime createdAt; + try + { + // 尝试直接读取为DateTime + createdAt = roomReader.GetDateTime(roomReader.GetOrdinal("CreatedAt")); + } + catch (InvalidCastException) + { + // 如果不是DateTime类型,尝试作为数字处理 + try + { + long createdAtTimestamp = roomReader.GetInt64(roomReader.GetOrdinal("CreatedAt")); + Console.WriteLine($"原始时间戳值: {createdAtTimestamp}"); + + // 尝试不同的时间戳单位 + if (createdAtTimestamp > 1000000000000) // 毫秒 + { + createdAt = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds(createdAtTimestamp); + } + else if (createdAtTimestamp > 1000000000) // 秒 + { + createdAt = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(createdAtTimestamp); + } + else // 假设是天 + { + createdAt = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddDays(createdAtTimestamp); + } + } + catch (Exception ex) + { + Console.WriteLine($"时间戳转换失败: {ex.Message}"); + createdAt = DateTime.MinValue; // 设置默认值 + } + } + + int status = roomReader.GetInt32(roomReader.GetOrdinal("Status")); + + // 查询该房间的玩家 + List players = GetRoomPlayers(id, connectionString); + List spectators = GetRoomSpectators(id, connectionString); + + // 格式化输出 + Console.WriteLine($"{id} | {name} | {createdAt} | {status} | {string.Join(',', players)} | {string.Join(',', spectators)}"); + } + catch (Exception ex) + { + Console.WriteLine($"处理房间数据时出错: {ex.Message}"); + } + } + } + } + } + catch (Exception ex) + { + Console.WriteLine($"发生错误: {ex.Message}"); + } + } + + // 查询表结构 + static void QueryTableStructure(string tableName, string connectionString) + { + try + { + using (var connection = new NpgsqlConnection(connectionString)) + { + connection.Open(); + string query = $"SELECT column_name FROM information_schema.columns WHERE table_name = '{tableName}'"; + using (var command = new NpgsqlCommand(query, connection)) + using (var reader = command.ExecuteReader()) + { + Console.WriteLine($"\n表 {tableName} 的列名:"); + while (reader.Read()) + { + Console.WriteLine(reader.GetString(0)); + } + } + } + } + catch (Exception ex) + { + Console.WriteLine($"查询表 {tableName} 结构失败: {ex.Message}"); + } + } + + // 获取房间玩家 + static List GetRoomPlayers(Guid roomId, string connectionString) + { + List players = new List(); + try + { + using (var connection = new NpgsqlConnection(connectionString)) + { + connection.Open(); + string query = "SELECT \"NickName\" FROM public.\"Players\" WHERE \"RoomId\" = @RoomId"; + using (var command = new NpgsqlCommand(query, connection)) + { + command.Parameters.AddWithValue("@RoomId", roomId); + using (var reader = command.ExecuteReader()) + { + while (reader.Read()) + { + players.Add(reader.GetString(0)); + } + } + } + } + } + catch (Exception ex) + { + Console.WriteLine($"获取房间玩家失败: {ex.Message}"); + } + return players; + } + + // 获取房间观众 + static List GetRoomSpectators(Guid roomId, string connectionString) + { + List spectators = new List(); + try + { + using (var connection = new NpgsqlConnection(connectionString)) + { + connection.Open(); + string query = "SELECT \"NickName\" FROM public.\"Spectators\" WHERE \"RoomId\" = @RoomId"; + using (var command = new NpgsqlCommand(query, connection)) + { + command.Parameters.AddWithValue("@RoomId", roomId); + using (var reader = command.ExecuteReader()) + { + while (reader.Read()) + { + spectators.Add(reader.GetString(0)); + } + } + } + } + } + catch (Exception ex) + { + Console.WriteLine($"获取房间观众失败: {ex.Message}"); + } + return spectators; + } +} \ No newline at end of file diff --git a/HealthCheckTest/HealthCheckTest.csproj b/HealthCheckTest/HealthCheckTest.csproj new file mode 100644 index 0000000000000000000000000000000000000000..91b464afeacc105176e61d05a1def7d10b514917 --- /dev/null +++ b/HealthCheckTest/HealthCheckTest.csproj @@ -0,0 +1,10 @@ + + + + Exe + net8.0 + enable + enable + + + diff --git a/HealthCheckTest/Program.cs b/HealthCheckTest/Program.cs new file mode 100644 index 0000000000000000000000000000000000000000..3751555cbd32d09340c8cb7b75ce8311c4330054 --- /dev/null +++ b/HealthCheckTest/Program.cs @@ -0,0 +1,2 @@ +// See https://aka.ms/new-console-template for more information +Console.WriteLine("Hello, World!"); diff --git a/TestDbConnection.cs b/TestDbConnection.cs new file mode 100644 index 0000000000000000000000000000000000000000..3d0d2b8acbf6da373acd9f65601eea55f8f8ea7c --- /dev/null +++ b/TestDbConnection.cs @@ -0,0 +1,27 @@ +using System; +using System.Threading.Tasks; +using Npgsql; + +class Program +{ + static async Task Main() + { + string connectionString = "Host=39.105.7.196;Port=5432;Database=TerritoryGame;Username=postgres;Password=xyq0716"; + + try + { + await using var conn = new NpgsqlConnection(connectionString); + Console.WriteLine("Opening connection..."); + await conn.OpenAsync(); + Console.WriteLine("Connection opened successfully."); + + await using var cmd = new NpgsqlCommand("SELECT COUNT(*) FROM GameRooms", conn); + var count = await cmd.ExecuteScalarAsync(); + Console.WriteLine($"Number of rooms in database: {count}"); + } + catch (Exception ex) + { + Console.WriteLine($"Error: {ex.Message}"); + } + } +} \ No newline at end of file diff --git a/TestDbConnection.csproj b/TestDbConnection.csproj new file mode 100644 index 0000000000000000000000000000000000000000..8eedfa13efe7a444ee1797d576b497b61de83e66 --- /dev/null +++ b/TestDbConnection.csproj @@ -0,0 +1,16 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + + + \ No newline at end of file diff --git a/TestDbConnectionDir/TestDbConnection.cs b/TestDbConnectionDir/TestDbConnection.cs new file mode 100644 index 0000000000000000000000000000000000000000..44e2a68773ae23693062d7b173a1d46e23b60726 --- /dev/null +++ b/TestDbConnectionDir/TestDbConnection.cs @@ -0,0 +1,140 @@ +using StackExchange.Redis; +using System; +using System.Threading.Tasks; + +class Program +{ + static async Task Main(string[] args) + { + try + { + // 从配置中获取Redis连接字符串 + string redisHost = "39.105.7.196"; + int redisPort = 6379; + string redisConnectionString = $"{redisHost}:{redisPort}"; + Console.WriteLine($"尝试连接到Redis服务器: {redisConnectionString}"); + + // 检查服务器是否可达 + Console.WriteLine("正在检查服务器可达性..."); + try + { + // 使用Ping命令检查服务器是否可达 + var ping = new System.Net.NetworkInformation.Ping(); + var reply = ping.Send(redisHost, 5000); // 5秒超时 + if (reply.Status == System.Net.NetworkInformation.IPStatus.Success) + { + Console.WriteLine($"服务器 {redisHost} 可达,延迟: {reply.RoundtripTime}ms"); + } + else + { + Console.WriteLine($"服务器 {redisHost} 不可达,状态: {reply.Status}"); + } + } + catch (Exception ex) + { + Console.WriteLine($"Ping测试失败: {ex.Message}"); + } + + + + // 创建连接配置 + ConfigurationOptions options = ConfigurationOptions.Parse(redisConnectionString); + options.AbortOnConnectFail = false; // 允许连接失败后继续重试 + options.ConnectTimeout = 10000; // 设置连接超时时间为10秒 + options.SyncTimeout = 10000; // 设置同步操作超时时间为10秒 + options.AsyncTimeout = 10000; // 设置异步操作超时时间为10秒 + options.ConnectRetry = 3; // 启用连接重试,最多重试3次 + options.AllowAdmin = true; // 允许管理员操作 + options.Ssl = false; // 不使用SSL + options.ClientName = "TestClient"; + + Console.WriteLine("正在尝试连接到Redis服务器..."); + // 测试Redis端口连接 + try + { + using (var client = new System.Net.Sockets.TcpClient()) + { + Console.WriteLine($"正在尝试连接到 {redisHost}:{redisPort}..."); + var result = client.BeginConnect(redisHost, redisPort, null, null); + var success = result.AsyncWaitHandle.WaitOne(10000); // 10秒超时 + if (!success) + { + Console.WriteLine($"Redis服务器端口连接失败: 无法在10秒内连接到 {redisHost}:{redisPort}"); + throw new Exception($"Failed to connect to {redisHost}:{redisPort} within timeout period"); + } + client.EndConnect(result); + Console.WriteLine($"Redis服务器端口连接成功: 已连接到 {redisHost}:{redisPort}"); + } + } + catch (Exception ex) + { + Console.WriteLine($"Redis服务器端口连接异常: {ex.Message}"); + throw; + } + + // 创建连接 + ConnectionMultiplexer redis = await ConnectionMultiplexer.ConnectAsync(options); + Console.WriteLine("Redis连接成功!"); + + // 获取服务器信息 + var server = redis.GetServer("39.105.7.196", 6379); + try + { + var info = server.Info(); + Console.WriteLine("Redis服务器信息:"); + // 简化版本信息获取 + string version = "未知"; + var serverInfo = info.FirstOrDefault(i => i.Key == "server"); + if (serverInfo != null) + { + var versionEntry = serverInfo.FirstOrDefault(v => v.Key == "redis_version"); + if (versionEntry.Key != null) + { + version = versionEntry.Value; + } + } + Console.WriteLine($"版本: {version}"); + } + catch (Exception ex) + { + Console.WriteLine($"获取服务器信息失败: {ex.Message}"); + } + + // 获取数据库 + IDatabase db = redis.GetDatabase(); + + // 测试Ping + var pingResult = await db.PingAsync(); + Console.WriteLine($"Ping结果: {pingResult.TotalMilliseconds}ms"); + + // 测试设置和获取值 + string key = "test_key"; + string value = "Hello Redis!"; + bool setResult = await db.StringSetAsync(key, value); + Console.WriteLine($"设置键: {key}, 值: {value}, 结果: {setResult}"); + + string retrievedValue = await db.StringGetAsync(key); + Console.WriteLine($"获取键: {key}, 值: {retrievedValue}"); + + // 测试获取客户端列表 + try + { + var clients = server.ClientList(); + Console.WriteLine($"当前连接的客户端数量: {clients.Length}"); + } + catch (Exception ex) + { + Console.WriteLine($"获取客户端列表失败: {ex.Message}"); + } + + // 断开连接 + redis.Close(); + Console.WriteLine("Redis连接已关闭"); + } + catch (Exception ex) + { + Console.WriteLine($"Redis连接失败: {ex.Message}"); + Console.WriteLine($"错误详情: {ex.InnerException?.Message}"); + } + } +} \ No newline at end of file diff --git a/TestDbConnectionDir/TestDbConnection.csproj b/TestDbConnectionDir/TestDbConnection.csproj new file mode 100644 index 0000000000000000000000000000000000000000..bc999e3e1c0b7e0f7a7d604afbbeba4e9e3a6133 --- /dev/null +++ b/TestDbConnectionDir/TestDbConnection.csproj @@ -0,0 +1,14 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + \ No newline at end of file diff --git a/TestRedisConnection.cs b/TestRedisConnection.cs new file mode 100644 index 0000000000000000000000000000000000000000..f43a3ee9348330d41ed3e88cd520bdada496aa9f --- /dev/null +++ b/TestRedisConnection.cs @@ -0,0 +1,41 @@ +using StackExchange.Redis; +using System; +using System.Threading.Tasks; + +class Program +{ + static async Task Main(string[] args) + { + try + { + // 从配置中获取Redis连接字符串 + string redisConnectionString = "39.105.7.196:6379"; + Console.WriteLine($"尝试连接到Redis服务器: {redisConnectionString}"); + + // 创建连接 + ConnectionMultiplexer redis = await ConnectionMultiplexer.ConnectAsync(redisConnectionString); + Console.WriteLine("Redis连接成功!"); + + // 获取数据库 + IDatabase db = redis.GetDatabase(); + + // 测试设置和获取值 + string key = "test_key"; + string value = "Hello Redis!"; + await db.StringSetAsync(key, value); + Console.WriteLine($"设置键: {key}, 值: {value}"); + + string retrievedValue = await db.StringGetAsync(key); + Console.WriteLine($"获取键: {key}, 值: {retrievedValue}"); + + // 断开连接 + redis.Close(); + Console.WriteLine("Redis连接已关闭"); + } + catch (Exception ex) + { + Console.WriteLine($"Redis连接失败: {ex.Message}"); + Console.WriteLine($"错误详情: {ex.InnerException?.Message}"); + } + } +} \ No newline at end of file diff --git a/TestRedisConnection.csproj b/TestRedisConnection.csproj new file mode 100644 index 0000000000000000000000000000000000000000..df07d8a4741dbed748176026ad58f5a9f45aa013 --- /dev/null +++ b/TestRedisConnection.csproj @@ -0,0 +1,16 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + + + \ No newline at end of file diff --git a/backend/CompleteDITest.cs b/backend/CompleteDITest.cs new file mode 100644 index 0000000000000000000000000000000000000000..6a53e9f57ccb38ca911aa6e0a2beb66d42131524 --- /dev/null +++ b/backend/CompleteDITest.cs @@ -0,0 +1,58 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Configuration; +using System; +using System.IO; +using TerritoryGame.Application.Services; +using TerritoryGame.Domain.Services; +using TerritoryGame.Infrastructure; +using TerritoryGame.Infrastructure.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Caching.StackExchangeRedis; +using StackExchange.Redis; + +class CompleteDITest +{ + static void Main(string[] args) + { + // 创建配置 + var configuration = new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile(Path.Combine(Directory.GetParent(Directory.GetCurrentDirectory()).Parent.Parent.FullName, "backend", "src", "TerritoryGame.Api", "appsettings.json")) + .Build(); + + // 创建服务集合 + var services = new ServiceCollection(); + + // 添加配置 + services.AddSingleton(configuration); + + // 注册Infrastructure服务 + services.AddInfrastructure(configuration); + + // 构建服务提供程序 + var serviceProvider = services.BuildServiceProvider(); + + // 解析服务 + try + { + Console.WriteLine("开始解析IGameService..."); + var gameService = serviceProvider.GetRequiredService(); + Console.WriteLine("成功解析IGameService"); + + // 测试服务功能 + Console.WriteLine("开始创建房间..."); + var room = gameService.CreateRoomAsync("测试房间").Result; + Console.WriteLine($"成功创建房间: {room.Name}, ID: {room.Id}"); + } + catch (Exception ex) + { + Console.WriteLine($"解析IGameService失败: {ex.Message}"); + Console.WriteLine(ex.StackTrace); + if (ex.InnerException != null) + { + Console.WriteLine($"内部异常: {ex.InnerException.Message}"); + Console.WriteLine(ex.InnerException.StackTrace); + } + } + } +} \ No newline at end of file diff --git a/backend/CompleteDITest/CompleteDITest.csproj b/backend/CompleteDITest/CompleteDITest.csproj new file mode 100644 index 0000000000000000000000000000000000000000..62a745c0d7afd1efc928aeb14a20817b7b3bdd03 --- /dev/null +++ b/backend/CompleteDITest/CompleteDITest.csproj @@ -0,0 +1,25 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + + + + + + + + + + + + diff --git a/backend/CompleteDITest/Program.cs b/backend/CompleteDITest/Program.cs new file mode 100644 index 0000000000000000000000000000000000000000..f7002a93b659d87b8e24594682b7df4147a9f83e --- /dev/null +++ b/backend/CompleteDITest/Program.cs @@ -0,0 +1,58 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Configuration; +using System; +using System.IO; +using TerritoryGame.Application.Services; +using TerritoryGame.Domain.Services; +using TerritoryGame.Infrastructure; +using TerritoryGame.Infrastructure.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Caching.StackExchangeRedis; +using StackExchange.Redis; + +class Program +{ + static void Main(string[] args) + { + // 创建配置 + var configuration = new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("c:\\Users\\Asus\\Desktop\\lightweight-realtime-collab-app-class1-group2\\backend\\src\\TerritoryGame.Api\\appsettings.json") + .Build(); + + // 创建服务集合 + var services = new ServiceCollection(); + + // 添加配置 + services.AddSingleton(configuration); + + // 注册Infrastructure服务 + services.AddInfrastructure(configuration); + + // 构建服务提供程序 + var serviceProvider = services.BuildServiceProvider(); + + // 解析服务 + try + { + Console.WriteLine("开始解析IGameService..."); + var gameService = serviceProvider.GetRequiredService(); + Console.WriteLine("成功解析IGameService"); + + // 测试服务功能 + Console.WriteLine("开始创建房间..."); + var room = gameService.CreateRoomAsync("测试房间", null, 6).Result; + Console.WriteLine($"成功创建房间: {room.Name}, ID: {room.Id}"); + } + catch (Exception ex) + { + Console.WriteLine($"解析IGameService失败: {ex.Message}"); + Console.WriteLine(ex.StackTrace); + if (ex.InnerException != null) + { + Console.WriteLine($"内部异常: {ex.InnerException.Message}"); + Console.WriteLine(ex.InnerException.StackTrace); + } + } + } +} diff --git a/backend/src/TerritoryGame.Api/Hubs/GameHub.cs b/backend/src/TerritoryGame.Api/Hubs/GameHub.cs index 1f8b6572232a10c34da9f1ff6a21288eebf412ce..5099d78f2c381fb38ff6b400494a83b009290bdd 100644 --- a/backend/src/TerritoryGame.Api/Hubs/GameHub.cs +++ b/backend/src/TerritoryGame.Api/Hubs/GameHub.cs @@ -2,27 +2,58 @@ using Microsoft.AspNetCore.SignalR; using TerritoryGame.Domain.Entities; using DomainServices = TerritoryGame.Domain.Services; using System.Security.Claims; +using Microsoft.Extensions.Logging; namespace TerritoryGame.Api.Hubs; public class GameHub : Hub { private readonly DomainServices.IGameService _gameService; + private readonly ILogger _logger; - public GameHub(DomainServices.IGameService gameService) + public GameHub(DomainServices.IGameService gameService, ILogger logger) { _gameService = gameService; + _logger = logger; } // 获取房间列表 public async Task GetRoomList() { try { + Console.WriteLine("GetRoomList method called"); var rooms = await _gameService.GetAvailableRoomsAsync(); - await Clients.Caller.SendAsync("RoomListUpdated", new { rooms }); - } - catch (Exception ex) - { + Console.WriteLine($"Retrieved {rooms.Count} rooms from service"); + // 输出前3个房间的详细信息用于调试 + for (int i = 0; i < Math.Min(rooms.Count, 3); i++) + { + var room = rooms[i]; + Console.WriteLine($"Room {i+1}: {room.Name}, Status: {room.Status}, Players: {room.Players.Count}/{room.MaxPlayers}"); + } + // 确保每个房间都包含CurrentPlayers属性 + var formattedRooms = rooms.Select(room => new { + Id = room.Id, + Name = room.Name, + Password = room.Password, + MaxPlayers = room.MaxPlayers, + CurrentPlayers = room.Players.Count, + SpectatorsCount = room.Spectators.Count, + Status = room.Status.ToString(), + GameDuration = room.GameDuration, + CreatedAt = room.CreatedAt, + UpdatedAt = room.UpdatedAt, + HasPassword = !string.IsNullOrEmpty(room.Password) + }).ToList(); + Console.WriteLine($"Formatted {formattedRooms.Count} rooms to send to client"); + // 输出前3个格式化后的房间信息 + for (int i = 0; i < Math.Min(formattedRooms.Count, 3); i++) + { + var room = formattedRooms[i]; + Console.WriteLine($"Formatted Room {i+1}: {room.Name}, Status: {room.Status}, Players: {room.CurrentPlayers}/{room.MaxPlayers}"); + } + await Clients.Caller.SendAsync("RoomListUpdated", new { rooms = formattedRooms }); + } catch (Exception ex) { + Console.WriteLine($"Error in GetRoomList: {ex.Message}"); await Clients.Caller.SendAsync("GetRoomListFailed", new { success = false, message = ex.Message }); } } @@ -321,10 +352,39 @@ public class GameHub : Hub Context.Items["RoomId"] = room.Id; await Clients.Group(room.Id.ToString()).SendAsync("PlayerJoined", player); await Clients.Others.SendAsync("RoomListUpdated", await _gameService.GetAvailableRoomsAsync()); + } catch (Exception ex) { + await Clients.Caller.SendAsync("QuickStartResult", new { success = false, message = ex.Message }); } - catch (Exception ex) + } + + // 连接建立时调用 + public override async Task OnConnectedAsync() + { + _logger.LogInformation("Client connected: {ConnectionId}", Context.ConnectionId); + await base.OnConnectedAsync(); + } + + // 连接断开时调用 + public override async Task OnDisconnectedAsync(Exception exception) + { + _logger.LogInformation("Client disconnected: {ConnectionId}, Exception: {Exception}", Context.ConnectionId, exception?.Message); + + // 处理玩家断开连接的逻辑 + if (Context.Items.TryGetValue("PlayerId", out var playerIdObj) && playerIdObj is Guid playerId && + Context.Items.TryGetValue("RoomId", out var roomIdObj) && roomIdObj is Guid roomId) { - await Clients.Caller.SendAsync("QuickStartResult", new { success = false, message = ex.Message }); + try + { + await NotifyPlayerLeft(roomId.ToString(), playerId); + // 从房间中移除玩家 + await _gameService.LeaveRoomAsync(roomId, playerId); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error handling player disconnect: {ConnectionId}", Context.ConnectionId); + } } + + await base.OnDisconnectedAsync(exception); } } \ No newline at end of file diff --git a/backend/src/TerritoryGame.Api/Program.cs b/backend/src/TerritoryGame.Api/Program.cs index 46e60c8464748df0efc9ec1b8fb09bf7570a8a4b..7959d20a3d3750003035e0e08bcfc90deb1a40ce 100644 --- a/backend/src/TerritoryGame.Api/Program.cs +++ b/backend/src/TerritoryGame.Api/Program.cs @@ -38,14 +38,13 @@ builder.Services.AddSwaggerGen(c => // Add SignalR builder.Services.AddSignalR(); -// Register application services -builder.Services.AddScoped(); +// Application services are registered in AddInfrastructure method builder.Services.AddCors(options => { options.AddPolicy("AllowAll", builder => { - builder.WithOrigins("http://localhost:5173", "http://localhost:5120") + builder.WithOrigins("http://localhost:5173", "http://localhost:5174", "http://localhost:5120") .SetIsOriginAllowedToAllowWildcardSubdomains() .AllowAnyMethod() .AllowAnyHeader() diff --git a/backend/src/TerritoryGame.Api/appsettings.json b/backend/src/TerritoryGame.Api/appsettings.json index b96e1644ba602636da6c8f5ace1f53a3337b07a3..564a2971bf4c8b5ca24c08e04ad84128edf326cd 100644 --- a/backend/src/TerritoryGame.Api/appsettings.json +++ b/backend/src/TerritoryGame.Api/appsettings.json @@ -5,8 +5,8 @@ }, "Logging": { "LogLevel": { - "Default": "Information", - "Microsoft.AspNetCore": "Warning" + "Default": "Debug", + "Microsoft.AspNetCore": "Debug" } }, "AllowedHosts": "*" diff --git a/backend/src/TerritoryGame.Application/Services/GameService.cs b/backend/src/TerritoryGame.Application/Services/GameService.cs index dfb18c3932ba4d9006d4459a63a041951b42506d..2baf8feff1ae043876628776bcf9463f90851888 100644 --- a/backend/src/TerritoryGame.Application/Services/GameService.cs +++ b/backend/src/TerritoryGame.Application/Services/GameService.cs @@ -46,13 +46,14 @@ public class GameService : DomainServices.IGameService try { - // 缓存房间信息 - await CacheRoomAsync(room); + // 优化:异步缓存不阻塞主线程 + _ = CacheRoomAsync(room); } catch (RedisConnectionException ex) { // Redis连接失败,记录日志但不影响程序运行 - Console.WriteLine($"Redis connection error: {ex.Message}"); + Console.WriteLine($"Redis connection error in CacheRoomAsync: {ex.Message}"); + Console.WriteLine($"Redis error details: {ex.InnerException?.Message ?? "No inner exception"}"); } return room; @@ -95,38 +96,105 @@ public class GameService : DomainServices.IGameService try { // 先从缓存获取 - var cachedRooms = await _cache.GetStringAsync("available_rooms"); - if (!string.IsNullOrEmpty(cachedRooms)) + List rooms = null; + try + { + // 优化:添加异步操作超时处理 + var cacheTask = _cache.GetStringAsync("available_rooms"); + if (await Task.WhenAny(cacheTask, Task.Delay(1000)) == cacheTask) + { + var cachedRooms = await cacheTask; + if (!string.IsNullOrEmpty(cachedRooms)) + { + rooms = JsonSerializer.Deserialize>(cachedRooms); + return rooms; + } + } + else + { + Console.WriteLine("Cache retrieval timed out"); + } + } + catch (RedisConnectionException ex) { - return JsonSerializer.Deserialize>(cachedRooms); + Console.WriteLine($"Redis connection error when reading cache: {ex.Message}"); + Console.WriteLine($"Redis error details: {ex.InnerException?.Message ?? "No inner exception"}"); + // 优化:添加简单的重试逻辑 + try + { + await Task.Delay(200); // 短暂延迟后重试 + var cachedRooms = await _cache.GetStringAsync("available_rooms"); + if (!string.IsNullOrEmpty(cachedRooms)) + { + rooms = JsonSerializer.Deserialize>(cachedRooms); + return rooms; + } + } + catch (Exception retryEx) + { + Console.WriteLine($"Retry failed: {retryEx.Message}"); + } + } + catch (Exception ex) + { + Console.WriteLine($"Error reading from cache: {ex.Message}"); } - // 缓存未命中,从数据库获取 - var rooms = await _context.GameRooms + // 缓存未命中或读取失败,从数据库获取 + var roomsFromDb = await _context.GameRooms .Include(r => r.Players) .Include(r => r.Spectators) + .Where(r => r.Status == GameStatus.Waiting || r.Status == GameStatus.Playing) .OrderByDescending(r => r.CreatedAt) .ToListAsync(); + // 如果没有房间,创建一个测试房间用于调试 + if (roomsFromDb.Count == 0) + { + var testRoom = new GameRoom + { + Name = "Test Room", + MaxPlayers = 6, + Status = GameStatus.Waiting, + CreatedAt = DateTime.UtcNow, + UpdatedAt = DateTime.UtcNow, + GameDuration = 180 + }; + _context.GameRooms.Add(testRoom); + await _context.SaveChangesAsync(); + roomsFromDb = new List { testRoom }; + } + // 更新缓存 try { - await _cache.SetStringAsync( - "available_rooms", - JsonSerializer.Serialize(rooms), - new DistributedCacheEntryOptions { SlidingExpiration = TimeSpan.FromSeconds(10) } - ); + // 优化:调整缓存策略,增加绝对过期时间 + var options = new DistributedCacheEntryOptions + { + AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5), + SlidingExpiration = TimeSpan.FromMinutes(1) + }; + + // 优化:使用更高效的序列化选项 + var serializedRooms = JsonSerializer.Serialize(roomsFromDb, new JsonSerializerOptions { WriteIndented = false }); + await _cache.SetStringAsync("available_rooms", serializedRooms, options); } catch (RedisConnectionException ex) { - Console.WriteLine($"Redis connection error: {ex.Message}"); + Console.WriteLine($"Redis connection error when updating cache: {ex.Message}"); + Console.WriteLine($"Redis error details: {ex.InnerException?.Message ?? "No inner exception"}"); + } + catch (Exception ex) + { + Console.WriteLine($"Error updating cache: {ex.Message}"); } - return rooms; + return roomsFromDb; } catch (Exception ex) { Console.WriteLine($"Error getting available rooms: {ex.Message}"); + Console.WriteLine($"Error stack trace: {ex.StackTrace}"); throw; } } @@ -134,25 +202,51 @@ public class GameService : DomainServices.IGameService // 获取房间 public async Task GetRoomByIdAsync(Guid roomId) { + // 先从缓存获取 try { - // 先从缓存获取 - var cachedRoom = await _cache.GetStringAsync($"room:{roomId}"); - if (!string.IsNullOrEmpty(cachedRoom)) + // 优化:添加异步操作超时处理 + var cacheTask = _cache.GetStringAsync($"room:{roomId}"); + if (await Task.WhenAny(cacheTask, Task.Delay(1000)) == cacheTask) { - return JsonSerializer.Deserialize(cachedRoom)! - ?? throw new InvalidOperationException("Failed to deserialize cached room"); + var cachedRoom = await cacheTask; + if (!string.IsNullOrEmpty(cachedRoom)) + { + return JsonSerializer.Deserialize(cachedRoom)! + ?? throw new InvalidOperationException("Failed to deserialize cached room"); + } + } + else + { + Console.WriteLine("Cache retrieval timed out for room: {0}", roomId); } } catch (RedisConnectionException ex) { // Redis连接失败,记录日志并继续从数据库获取 - Console.WriteLine($"Redis connection error: {ex.Message}"); + Console.WriteLine($"Redis connection error when reading cache: {ex.Message}"); + Console.WriteLine($"Redis error details: {ex.InnerException?.Message ?? "No inner exception"}"); + // 优化:添加简单的重试逻辑 + try + { + await Task.Delay(200); // 短暂延迟后重试 + var cachedRoom = await _cache.GetStringAsync($"room:{roomId}"); + if (!string.IsNullOrEmpty(cachedRoom)) + { + return JsonSerializer.Deserialize(cachedRoom)! + ?? throw new InvalidOperationException("Failed to deserialize cached room"); + } + } + catch (Exception retryEx) + { + Console.WriteLine($"Retry failed: {retryEx.Message}"); + } } // 从数据库获取 var room = await _context.GameRooms .Include(r => r.Players) + .Include(r => r.Spectators) // 优化:包含观战者数据 .FirstOrDefaultAsync(r => r.Id == roomId); if (room == null) @@ -177,51 +271,102 @@ public class GameService : DomainServices.IGameService // 加入房间 public async Task JoinRoomAsync(Guid roomId, Player player) { - var room = await GetRoomByIdAsync(roomId); - - // 检查房间是否已满 - if (room.Players.Count >= room.MaxPlayers) + // 使用事务确保数据一致性 + using var transaction = await _context.Database.BeginTransactionAsync(); + try { - throw new InvalidOperationException("Room is full"); - } + // 直接查询房间,避免额外的方法调用开销 + var room = await _context.GameRooms + .Include(r => r.Players) + .FirstOrDefaultAsync(r => r.Id == roomId); - // 检查玩家是否已在房间中 - if (room.Players.Any(p => p.Id == player.Id)) - { - throw new InvalidOperationException("Player is already in the room"); - } + if (room == null) + { + throw new KeyNotFoundException($"Room with ID {roomId} not found"); + } - // 添加玩家到房间 - room.AddPlayer(player); - _context.Players.Add(player); - await _context.SaveChangesAsync(); + // 检查房间是否已满 + if (room.Players.Count >= room.MaxPlayers) + { + throw new InvalidOperationException("Room is full"); + } - // 缓存更新后的房间信息 - await CacheRoomAsync(room); + // 检查玩家是否已在房间中 + if (room.Players.Any(p => p.Id == player.Id)) + { + throw new InvalidOperationException("Player is already in the room"); + } - return room; + // 添加玩家到房间 + room.AddPlayer(player); + _context.Players.Add(player); + await _context.SaveChangesAsync(); + + // 清除旧缓存并缓存更新后的房间信息 + try + { + await _cache.RemoveAsync($"room:{room.Id}"); + await _cache.RemoveAsync("available_rooms"); + await CacheRoomAsync(room); + } + catch (RedisConnectionException ex) + { + // Redis连接失败,记录日志但不影响程序运行 + Console.WriteLine($"Redis connection error in JoinRoomAsync: {ex.Message}"); + Console.WriteLine($"Redis error details: {ex.InnerException?.Message}"); + } + + await transaction.CommitAsync(); + return room; + } + catch + { + await transaction.RollbackAsync(); + throw; + } } // 添加观战者 public async Task AddSpectatorAsync(Guid roomId, Spectator spectator) { - var room = await GetRoomByIdAsync(roomId); - - // 检查观战者是否已在房间中 - if (room.Spectators.Any(s => s.Id == spectator.Id)) + // 使用事务确保数据一致性 + using var transaction = await _context.Database.BeginTransactionAsync(); + try { - throw new InvalidOperationException("Spectator is already in the room"); - } + // 直接查询房间,避免额外的方法调用开销 + var room = await _context.GameRooms + .Include(r => r.Spectators) + .FirstOrDefaultAsync(r => r.Id == roomId); - // 添加观战者到房间 - room.AddSpectator(spectator); - _context.Spectators.Add(spectator); - await _context.SaveChangesAsync(); + if (room == null) + { + throw new KeyNotFoundException($"Room with ID {roomId} not found"); + } - // 缓存更新后的房间信息 - await CacheRoomAsync(room); + // 检查观战者是否已在房间中 + if (room.Spectators.Any(s => s.Id == spectator.Id)) + { + throw new InvalidOperationException("Spectator is already in the room"); + } - return room; + // 添加观战者到房间 + room.AddSpectator(spectator); + _context.Spectators.Add(spectator); + await _context.SaveChangesAsync(); + + // 清除旧缓存并缓存更新后的房间信息 + await _cache.RemoveAsync($"room:{room.Id}"); + await _cache.RemoveAsync("available_rooms"); + await CacheRoomAsync(room); + + await transaction.CommitAsync(); + return room; + } + catch + { + await transaction.RollbackAsync(); + throw; + } } // 离开房间 @@ -412,16 +557,24 @@ public class GameService : DomainServices.IGameService { var options = new DistributedCacheEntryOptions { - AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30) + AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(10), // 优化:缩短绝对过期时间 + SlidingExpiration = TimeSpan.FromMinutes(2) // 新增:滑动过期,2分钟未访问则刷新 }; - var roomJson = JsonSerializer.Serialize(room); + // 优化:使用更高效的序列化选项 + var roomJson = JsonSerializer.Serialize(room, new JsonSerializerOptions { WriteIndented = false }); await _cache.SetStringAsync($"room:{room.Id}", roomJson, options); } catch (RedisConnectionException ex) { // Redis连接失败,记录日志但不影响程序运行 - Console.WriteLine($"Redis connection error: {ex.Message}"); + Console.WriteLine($"Redis connection error in CacheRoomAsync: {ex.Message}"); + Console.WriteLine($"Redis error details: {ex.InnerException?.Message ?? "No inner exception"}"); + } + catch (Exception ex) + { + // 捕获其他异常 + Console.WriteLine($"Error caching room {room.Id}: {ex.Message}"); } } diff --git a/backend/src/TerritoryGame.Domain/Interfaces/IGameDbContext.cs b/backend/src/TerritoryGame.Domain/Interfaces/IGameDbContext.cs index ea40f9ca5689aadcee81b648892690ce946dd6e7..706febb4fb29b1940e057bd972881a11e79530d5 100644 --- a/backend/src/TerritoryGame.Domain/Interfaces/IGameDbContext.cs +++ b/backend/src/TerritoryGame.Domain/Interfaces/IGameDbContext.cs @@ -1,4 +1,5 @@ using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; using TerritoryGame.Domain.Entities; namespace TerritoryGame.Domain.Interfaces; @@ -10,5 +11,8 @@ public interface IGameDbContext DbSet PaintActions { get; set; } DbSet Spectators { get; set; } + // DatabaseFacade位于Infrastructure命名空间中 + DatabaseFacade Database { get; } + Task SaveChangesAsync(CancellationToken cancellationToken = default); } \ No newline at end of file diff --git a/backend/src/TerritoryGame.Infrastructure/Data/GameDbContext.cs b/backend/src/TerritoryGame.Infrastructure/Data/GameDbContext.cs index 8670e929a6bed47917884afcac5cd7a3ee7ee569..19165113335608790df20cb342efae36e71a6669 100644 --- a/backend/src/TerritoryGame.Infrastructure/Data/GameDbContext.cs +++ b/backend/src/TerritoryGame.Infrastructure/Data/GameDbContext.cs @@ -1,4 +1,5 @@ using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; using TerritoryGame.Domain.Entities; using TerritoryGame.Domain.Interfaces; @@ -16,6 +17,10 @@ public class GameDbContext : DbContext, IGameDbContext public DbSet PaintActions { get; set; } public DbSet Spectators { get; set; } + // 显式实现IGameDbContext接口的Database属性 + // 使用new关键字避免隐藏继承成员的警告 + public new DatabaseFacade Database => base.Database; + protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); diff --git a/backend/src/TerritoryGame.Infrastructure/DependencyInjection.cs b/backend/src/TerritoryGame.Infrastructure/DependencyInjection.cs index 37d0f0edda575d4133e9ba97afc60eff1a6727fe..3a84190ff9a547a2acabc954d78b761d771794d3 100644 --- a/backend/src/TerritoryGame.Infrastructure/DependencyInjection.cs +++ b/backend/src/TerritoryGame.Infrastructure/DependencyInjection.cs @@ -2,6 +2,7 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Caching.StackExchangeRedis; +using TerritoryGame.Infrastructure.HealthChecks; using TerritoryGame.Application.Services; using TerritoryGame.Application.Interfaces; using TerritoryGame.Domain.Services; @@ -31,28 +32,28 @@ public static class DependencyInjection // 创建Redis配置选项 var redisConfig = StackExchange.Redis.ConfigurationOptions.Parse(redisConnectionString); - // 设置连接超时为10秒 - redisConfig.ConnectTimeout = 10000; + // 连接优化配置 + redisConfig.ConnectTimeout = 5000; // 减少连接超时时间到5秒 + redisConfig.SyncTimeout = 5000; // 减少同步操作超时到5秒 + redisConfig.AsyncTimeout = 5000; // 减少异步操作超时到5秒 - // 设置同步操作超时为10秒 - redisConfig.SyncTimeout = 10000; + // 重试策略 + redisConfig.ConnectRetry = 3; // 重试次数 + redisConfig.ReconnectRetryPolicy = new StackExchange.Redis.ExponentialRetry(1000, 10); // 指数退避重试策略 - // 设置异步操作超时为10秒 - redisConfig.AsyncTimeout = 10000; - - // 启用连接重试 - redisConfig.ConnectRetry = 3; - - // 允许管理员操作 - redisConfig.AllowAdmin = true; - - // 配置SSL(如果需要) - redisConfig.Ssl = false; + // 其他配置 + redisConfig.AllowAdmin = true; // 允许管理员操作 + redisConfig.Ssl = false; // 禁用SSL,因为连接字符串中没有SSL参数 + redisConfig.AbortOnConnectFail = false; // 连接失败时不中断应用 options.ConfigurationOptions = redisConfig; options.InstanceName = "TerritoryGame_"; }); + // 注册自定义Redis健康检查 + services.AddHealthChecks() + .AddCheck("redis"); + // 注册服务 services.AddScoped(); services.AddScoped(); diff --git a/backend/src/TerritoryGame.Infrastructure/HealthChecks/RedisHealthCheck.cs b/backend/src/TerritoryGame.Infrastructure/HealthChecks/RedisHealthCheck.cs new file mode 100644 index 0000000000000000000000000000000000000000..b8e418cc3cb6861b422767e4be32aafde57a7624 --- /dev/null +++ b/backend/src/TerritoryGame.Infrastructure/HealthChecks/RedisHealthCheck.cs @@ -0,0 +1,38 @@ +using Microsoft.Extensions.Diagnostics.HealthChecks; +using StackExchange.Redis; +using System.Threading.Tasks; +using System.Threading; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Configuration; + +namespace TerritoryGame.Infrastructure.HealthChecks; + +public class RedisHealthCheck : IHealthCheck +{ + private readonly IConnectionMultiplexer _redisConnection; + private readonly ILogger _logger; + + public RedisHealthCheck(IConnectionMultiplexer redisConnection, ILogger logger) + { + _redisConnection = redisConnection; + _logger = logger; + } + + public Task CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default) + { + try + { + // 检查Redis连接是否健康 + var server = _redisConnection.GetServer(_redisConnection.GetEndPoints().First()); + var info = server.Info(); + + _logger.LogInformation("Redis health check passed"); + return Task.FromResult(HealthCheckResult.Healthy("Redis connection is healthy")); + } + catch (Exception ex) + { + _logger.LogError(ex, "Redis health check failed"); + return Task.FromResult(HealthCheckResult.Unhealthy("Redis connection is unhealthy", ex)); + } + } +} \ No newline at end of file diff --git a/backend/src/TerritoryGame.Infrastructure/TerritoryGame.Infrastructure.csproj b/backend/src/TerritoryGame.Infrastructure/TerritoryGame.Infrastructure.csproj index 724f028da9da9895efda86605e6c97607bb85ef5..a4aab94209880707bc0294aed06c69b8da0e0b60 100644 --- a/backend/src/TerritoryGame.Infrastructure/TerritoryGame.Infrastructure.csproj +++ b/backend/src/TerritoryGame.Infrastructure/TerritoryGame.Infrastructure.csproj @@ -11,8 +11,9 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - + + diff --git a/frontend/src/components/GameCanvas.vue b/frontend/src/components/GameCanvas.vue index be6c69078079ed28164eb1dd0c5520d93ff3f078..4146c97c307cf74a501724e9681da7228c61da0f 100644 --- a/frontend/src/components/GameCanvas.vue +++ b/frontend/src/components/GameCanvas.vue @@ -1,23 +1,30 @@ \ No newline at end of file