using Autofac; using Autofac.Extensions.DependencyInjection; using ChessGameHost.Extension; using ChessGameHost.Middleware; using ChessGameService; using Common; using Common.Request; using CommonService; using JWTHelper; using MessagePack; using Microsoft.AspNetCore.Diagnostics.HealthChecks; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Options; using MongoRepository.Config; using NLog.Extensions.Logging; using NLog.Web; using RedisHelper; using RedisService; using SharpAbp.Infrastructure.Api.Middleware; using System.Text.Json; using UserService; using static Common.Utils.DateTimeTools; using ChessGameHost.Services; Environment.SetEnvironmentVariable("SERVICE_NAME", Environment.GetEnvironmentVariable("SERVICE_NAME") ?? System.Reflection.Assembly.GetEntryAssembly()?.GetName().Name ?? "ChessGameHost"); Environment.SetEnvironmentVariable("INSTANCE_ID", Environment.GetEnvironmentVariable("INSTANCE_ID") ?? "default"); var builder = WebApplication.CreateBuilder(args); string instanceId = Environment.GetEnvironmentVariable("INSTANCE_ID") ?? "Unknown"; builder.Services.AddSingleton(sp => new AppInstanceId { Id = instanceId }); // Add services to the container. builder.Services.AddControllers(); builder.Logging.AddNLog(); builder.Host.UseNLog(); builder.Configuration.AddJsonFile(Path.Combine("Config", "system.json"), optional: true); builder.Services.Configure(builder.Configuration.GetSection(nameof(MongoDbSettings))); builder.Services.AddSingleton(sp => sp.GetRequiredService>().Value); builder.Services.AddSignalR(hubOptions => { hubOptions.MaximumReceiveMessageSize = 64 * 1024; // 64KB hubOptions.StreamBufferCapacity = 512; hubOptions.ClientTimeoutInterval = TimeSpan.FromSeconds(70); hubOptions.KeepAliveInterval = TimeSpan.FromSeconds(15); hubOptions.AddFilter(); hubOptions.AddFilter(); }).AddJsonProtocol(); builder.Services.Configure(x => { x.MultipartBodyLengthLimit = 1024 * 1024 * 16; }); builder.Services.AddMemoryCache(); builder.Services.AddControllers().AddJsonOptions(configure => { configure.JsonSerializerOptions.Converters.Add(new DatetimeJsonConverter()); }); builder.Services.AddSingleton(); builder.Services.AddSingleton, HubSend>(); builder.Services.AddSingleton(); builder.Services.AddAutoMapper(typeof(AutoMapperConfig)); builder.Services.AddHostedService(); #region Swagger builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo { Title = "ChessGameHost", Description = "象棋Socket接口", Version = "v1" }); foreach (var xml in System.IO.Directory.GetFiles(AppContext.BaseDirectory, "*.xml")) { try { c.IncludeXmlComments(xml, true); } catch { } } }); #endregion builder.Services.AddHostedService(); builder.Services.AddHealthChecks() .AddCheck("self", () => HealthCheckResult.Healthy(), tags: new[] { "self" }); builder.Services.AddCors(options => { options.AddPolicy("Cors", policy => { policy //.WithOrigins(urls) .SetIsOriginAllowed(_ => true) .AllowAnyHeader() //.WithHeaders("x-signalr-user-agent", "content-type", "authorization") .AllowAnyMethod() .AllowCredentials() ; }); }); #region jwt builder.Services.AddCustomJwt(builder.Configuration); #endregion #region redis builder.Services.AddRedisCacheSingleton(builder.Configuration); #endregion builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory()); builder.Host.ConfigureContainer(builder => { builder.RegisterModule(); }); #region Cap builder.Services.AddCap(builder.Configuration); #endregion var app = builder.Build(); using (var scope = app.Services.CreateScope()) { var redis = scope.ServiceProvider.GetRequiredService(); var chessService = scope.ServiceProvider.GetRequiredService(); var logger = scope.ServiceProvider.GetRequiredService>(); try { redis.ClearAllLoginUserIds(); var rooms = redis.GetAllChessRooms() ?? new List(); var resetRooms = 0; var disconnectedRooms = 0; var affectedUserIds = new HashSet(); var now = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); foreach (var room in rooms.Where(r => r?.users?.Count > 0)) { foreach (var user in room.users.Where(u => !string.IsNullOrWhiteSpace(u.userId))) affectedUserIds.Add(user.userId); if (room.state != 2) { chessService.ExitRoom(room); resetRooms++; continue; } foreach (var user in room.users) { user.IsLeave = true; user.DisconnectTime = now; user.Cid = string.Empty; } redis.SetChessRoom(room); disconnectedRooms++; } foreach (var userId in affectedUserIds) await chessService.UpdateUserGameType(userId, 0); } catch (Exception ex) { logger.LogError(ex, "[Startup] 清除象棋玩家登录 cid 失败(非关键,不影响启动)"); } } // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { } #region Swagger app.UseSwagger(c => c.RouteTemplate = "swagger/{documentName}/swagger.json"); app.UseSwaggerUI(c => { c.RoutePrefix = "swagger"; c.SwaggerEndpoint("v1/swagger.json", "ChessGameHost v1"); }); #endregion app.UseApiLogging(); app.UseRouting(); app.UseGlobalExceptionHandler(); app.UseStaticFiles(); app.UseCors("Cors"); app.UseAuthentication(); app.UseAuthorization(); app.MapHub("/chessgamehub", options => { options.Transports = Microsoft.AspNetCore.Http.Connections.HttpTransportType.WebSockets; }); app.MapControllers(); app.MapHealthChecks("/health", new HealthCheckOptions { Predicate = _ => true, ResponseWriter = async (context, report) => { context.Response.ContentType = "application/json"; var result = new { status = report.Status.ToString(), checks = report.Entries.Select(e => new { name = e.Key, status = e.Value.Status.ToString(), description = e.Value.Description, duration = e.Value.Duration.TotalMilliseconds }), totalDuration = report.TotalDuration.TotalMilliseconds }; await context.Response.WriteAsync(JsonSerializer.Serialize(result)); } }); app.Run();