diff --git a/src/CloudGaming/Api/CloudGaming.ExtApi/Controllers/MonitorController.cs b/src/CloudGaming/Api/CloudGaming.ExtApi/Controllers/MonitorController.cs new file mode 100644 index 0000000..790d167 --- /dev/null +++ b/src/CloudGaming/Api/CloudGaming.ExtApi/Controllers/MonitorController.cs @@ -0,0 +1,11 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; + +namespace CloudGaming.ExtApi.Controllers +{ + [Route("api/[controller]")] + [ApiController] + public class MonitorController : ControllerBase + { + } +} diff --git a/src/CloudGaming/Api/CloudGaming.ExtApi/Program.cs b/src/CloudGaming/Api/CloudGaming.ExtApi/Program.cs index f378234..e0815de 100644 --- a/src/CloudGaming/Api/CloudGaming.ExtApi/Program.cs +++ b/src/CloudGaming/Api/CloudGaming.ExtApi/Program.cs @@ -2,6 +2,7 @@ using CloudGaming.Code.AppExtend; using CloudGaming.Code.DataAccess.MultiTenantUtil; using CloudGaming.Code.Filter; using CloudGaming.Code.Game; +using CloudGaming.Code.Monitor; using HuanMeng.DotNetCore.MiddlewareExtend; using HuanMeng.DotNetCore.SwaggerUtile; @@ -86,6 +87,7 @@ builder.Services.AddSwaggerGen(c => builder.AddAppConfigClient(); //添加游戏服务 builder.AddPlayGameServer(); +builder.AddMonitorConfig(); var app = builder.Build(); // Configure the HTTP request pipeline. @@ -108,7 +110,7 @@ app.UseSwaggerUI(c => app.UseAuthorization(); //数据库中间件 -app.UseMultiTenant(); +app.UseMultiTenantExt(); app.MapControllers(); app.UseMiddlewareAll(); #region 默认请求 diff --git a/src/CloudGaming/Code/CloudGaming.Code/AppExtend/AppConfigurationExtend.cs b/src/CloudGaming/Code/CloudGaming.Code/AppExtend/AppConfigurationExtend.cs index 38a8847..aae4b50 100644 --- a/src/CloudGaming/Code/CloudGaming.Code/AppExtend/AppConfigurationExtend.cs +++ b/src/CloudGaming/Code/CloudGaming.Code/AppExtend/AppConfigurationExtend.cs @@ -53,6 +53,25 @@ namespace CloudGaming.Code.AppExtend return AppConfigs.FirstOrDefault().Value; } /// + /// 获取配置项 + /// + /// + /// + public static AppConfig GetAppConfig(Guid tenantId) + { + var appConfig = AppConfigs.Where(it => it.Value.TenantId == tenantId).Select(it => it.Value).FirstOrDefault(); + if (appConfig != null) + { + return appConfig; + } + if (AppConfigs.TryGetValue("default", out appConfig)) + { + return appConfig; + } + + return AppConfigs.FirstOrDefault().Value; + } + /// /// /// /// diff --git a/src/CloudGaming/Code/CloudGaming.Code/CloudGaming.Code.csproj b/src/CloudGaming/Code/CloudGaming.Code/CloudGaming.Code.csproj index cc5eb55..e6cba50 100644 --- a/src/CloudGaming/Code/CloudGaming.Code/CloudGaming.Code.csproj +++ b/src/CloudGaming/Code/CloudGaming.Code/CloudGaming.Code.csproj @@ -19,6 +19,9 @@ + + + diff --git a/src/CloudGaming/Code/CloudGaming.Code/DataAccess/MultiTenantUtil/MultiTenantExtMiddleware.cs b/src/CloudGaming/Code/CloudGaming.Code/DataAccess/MultiTenantUtil/MultiTenantExtMiddleware.cs new file mode 100644 index 0000000..58b11f5 --- /dev/null +++ b/src/CloudGaming/Code/CloudGaming.Code/DataAccess/MultiTenantUtil/MultiTenantExtMiddleware.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudGaming.Code.DataAccess.MultiTenantUtil; + +/// +/// 多租户中间件 +/// +public class MultiTenantExtMiddleware +{ + private readonly RequestDelegate _next; + public MultiTenantExtMiddleware(RequestDelegate next) + { + _next = next; + } + + + /// + /// 根据HttpContext获取并设置当前租户ID + /// + /// + /// + /// + /// + public virtual async Task Invoke(HttpContext context, + IServiceProvider _serviceProvider, + AppConfig appConfig) + { + AppConfig app = null; + if (context.Request.Headers.TryGetValue("tenantId", out var str)) + { + if (Guid.TryParse(str, out Guid tenantId)) + { + app = AppConfigurationExtend.GetAppConfig(tenantId); + } + } + if (app == null) + { + var host = context.Request.Host.Host; + app = AppConfigurationExtend.GetAppConfig(host); + } + if (string.IsNullOrEmpty(appConfig.Identifier)) + { + app.ToAppConfig(appConfig); + } + await _next.Invoke(context); + } +} diff --git a/src/CloudGaming/Code/CloudGaming.Code/DataAccess/MultiTenantUtil/MultiTenantExtension.cs b/src/CloudGaming/Code/CloudGaming.Code/DataAccess/MultiTenantUtil/MultiTenantExtension.cs index fa5831a..3bda5d1 100644 --- a/src/CloudGaming/Code/CloudGaming.Code/DataAccess/MultiTenantUtil/MultiTenantExtension.cs +++ b/src/CloudGaming/Code/CloudGaming.Code/DataAccess/MultiTenantUtil/MultiTenantExtension.cs @@ -58,6 +58,16 @@ namespace CloudGaming.Code.DataAccess.MultiTenantUtil { return app.UseMiddleware(); } + /// + /// 多租户IApplicationBuilder扩展 + /// + /// + /// + public static IApplicationBuilder UseMultiTenantExt(this IApplicationBuilder app) + { + return app.UseMiddleware(); + } + } } diff --git a/src/CloudGaming/Code/CloudGaming.Code/DataAccess/MultiTenantUtil/MultiTenantTenantMiddleware.cs b/src/CloudGaming/Code/CloudGaming.Code/DataAccess/MultiTenantUtil/MultiTenantTenantMiddleware.cs index 0785ef5..55a7218 100644 --- a/src/CloudGaming/Code/CloudGaming.Code/DataAccess/MultiTenantUtil/MultiTenantTenantMiddleware.cs +++ b/src/CloudGaming/Code/CloudGaming.Code/DataAccess/MultiTenantUtil/MultiTenantTenantMiddleware.cs @@ -7,39 +7,38 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace CloudGaming.Code.DataAccess.MultiTenantUtil +namespace CloudGaming.Code.DataAccess.MultiTenantUtil; + +/// +/// 多租户中间件 +/// +public class MultiTenantTenantMiddleware { - /// - /// 多租户中间件 - /// - public class MultiTenantTenantMiddleware + private readonly RequestDelegate _next; + public MultiTenantTenantMiddleware(RequestDelegate next) { - private readonly RequestDelegate _next; - public MultiTenantTenantMiddleware(RequestDelegate next) + _next = next; + } + + + /// + /// 根据HttpContext获取并设置当前租户ID + /// + /// + /// + /// + /// + public virtual async Task Invoke(HttpContext context, + IServiceProvider _serviceProvider, + AppConfig appConfig) + { + + var host = context.Request.Host.Host; + var app = AppConfigurationExtend.GetAppConfig(host); + if (string.IsNullOrEmpty(appConfig.Identifier)) { - _next = next; - } - - - /// - /// 根据HttpContext获取并设置当前租户ID - /// - /// - /// - /// - /// - public virtual async Task Invoke(HttpContext context, - IServiceProvider _serviceProvider, - AppConfig appConfig) - { - - var host = context.Request.Host.Host; - var app = AppConfigurationExtend.GetAppConfig(host); - if (string.IsNullOrEmpty(appConfig.Identifier)) - { - app.ToAppConfig(appConfig); - } - await _next.Invoke(context); + app.ToAppConfig(appConfig); } + await _next.Invoke(context); } } diff --git a/src/CloudGaming/Code/CloudGaming.Code/Game/PlayGameProcessor.cs b/src/CloudGaming/Code/CloudGaming.Code/Game/PlayGameProcessor.cs index 0e18b06..9cca940 100644 --- a/src/CloudGaming/Code/CloudGaming.Code/Game/PlayGameProcessor.cs +++ b/src/CloudGaming/Code/CloudGaming.Code/Game/PlayGameProcessor.cs @@ -1,6 +1,7 @@ using CloudGaming.Code.Contract; using CloudGaming.Code.DataAccess; using CloudGaming.Code.JY; +using CloudGaming.Code.Monitor; using CloudGaming.DtoModel.PlayGame; using HuanMeng.DotNetCore.Processors; @@ -125,8 +126,16 @@ public class PlayGameProcessor(IServiceProvider serviceProvider) : ThreadProcess user.PlayGameUserNotQueue(); await user.SaveChangesAsync(dao, redis).ConfigureAwait(false); } + if (!MonitorExtend.AppMonitorConfigs.TryGetValue(app.Identifier, out var appMonitorInfo)) + { + appMonitorInfo = new DtoModel.Other.AppMonitorInfo() { }; + MonitorExtend.AppMonitorConfigs.TryAdd(app.Identifier, appMonitorInfo); + } + //替换引用 + appMonitorInfo.PlayGameUserInfos = gameInfoList; + //状态统计 - var gameStatusStatistics = gameInfoList.GroupBy(it => it.GameStatus).ToDictionary(it => it.Key, it => it.Count());// .Select(it => new { GameStatus = it.Key, GameCount = it.Count() }).ToList(); + //var gameStatusStatistics = gameInfoList.GroupBy(it => it.GameStatus).ToDictionary(it => it.Key, it => it.Count());// .Select(it => new { GameStatus = it.Key, GameCount = it.Count() }).ToList(); } /// diff --git a/src/CloudGaming/Code/CloudGaming.Code/Monitor/MonitorExtend.cs b/src/CloudGaming/Code/CloudGaming.Code/Monitor/MonitorExtend.cs new file mode 100644 index 0000000..29bff36 --- /dev/null +++ b/src/CloudGaming/Code/CloudGaming.Code/Monitor/MonitorExtend.cs @@ -0,0 +1,50 @@ +using AgileConfig.Client; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using CloudGaming.Code.DataAccess.MultiTenantUtil; +using CloudGaming.DtoModel.Other; + +using Quartz; + +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudGaming.Code.Monitor; + +/// +/// 监控扩展类 +/// +public static class MonitorExtend +{ + /// + /// + /// + public static ConcurrentDictionary AppMonitorConfigs { get; set; } = new ConcurrentDictionary(); + + + public static WebApplicationBuilder AddMonitorConfig(this WebApplicationBuilder builder) + { + // 添加 Quartz 配置 + builder.Services.AddQuartz(q => + { + // 注册作业和触发器 + var jobKey = new JobKey("MonitorProcessor"); + q.AddJob(opts => opts.WithIdentity(jobKey)); + + q.AddTrigger(opts => opts + .ForJob(jobKey) + .WithIdentity("monitorTrigger") + .StartNow() + .WithSimpleSchedule(x => x.WithIntervalInSeconds(5).RepeatForever())); + }); + + // 添加 Quartz 托管服务 + builder.Services.AddQuartzHostedService(q => q.WaitForJobsToComplete = true); + + return builder; + } +} diff --git a/src/CloudGaming/Code/CloudGaming.Code/Monitor/MonitorProcessor.cs b/src/CloudGaming/Code/CloudGaming.Code/Monitor/MonitorProcessor.cs new file mode 100644 index 0000000..53a08fc --- /dev/null +++ b/src/CloudGaming/Code/CloudGaming.Code/Monitor/MonitorProcessor.cs @@ -0,0 +1,28 @@ +using Quartz; + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudGaming.Code.Monitor; + + +/// +/// +/// +public class MonitorProcessor : IJob +{ + public MonitorProcessor(IServiceProvider serviceProvider) + { + + } + + public Task Execute(IJobExecutionContext context) + { + Console.WriteLine($"MessageService:"); + //throw new NotImplementedException(); + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/src/CloudGaming/Code/CloudGaming.Code/Other/MonitorBLL.cs b/src/CloudGaming/Code/CloudGaming.Code/Other/MonitorBLL.cs new file mode 100644 index 0000000..1582713 --- /dev/null +++ b/src/CloudGaming/Code/CloudGaming.Code/Other/MonitorBLL.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudGaming.Code.Other +{ + /// + /// 监控类 + /// + public class MonitorBLL : CloudGamingBase + { + public MonitorBLL(IServiceProvider serviceProvider) : base(serviceProvider) + { + } + } +} diff --git a/src/CloudGaming/Model/CloudGaming.DtoModel/Account/User/UserInfoCache.cs b/src/CloudGaming/Model/CloudGaming.DtoModel/Account/User/UserInfoCache.cs index 24aa972..f1cda08 100644 --- a/src/CloudGaming/Model/CloudGaming.DtoModel/Account/User/UserInfoCache.cs +++ b/src/CloudGaming/Model/CloudGaming.DtoModel/Account/User/UserInfoCache.cs @@ -12,7 +12,7 @@ namespace CloudGaming.DtoModel.Account.User /// /// 用户缓存 /// - public class UserInfoCache : UserInfo + public class UserInfoCache : UserInfo { /// /// 最后一次实名认证时间 diff --git a/src/CloudGaming/Model/CloudGaming.DtoModel/Other/AppMonitorInfo.cs b/src/CloudGaming/Model/CloudGaming.DtoModel/Other/AppMonitorInfo.cs new file mode 100644 index 0000000..a1fd2f3 --- /dev/null +++ b/src/CloudGaming/Model/CloudGaming.DtoModel/Other/AppMonitorInfo.cs @@ -0,0 +1,72 @@ +using CloudGaming.DtoModel.Account.User; +using CloudGaming.DtoModel.PlayGame; + +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudGaming.DtoModel.Other; + +/// +/// app监控数据 +/// +public class AppMonitorInfo +{ + /// + /// 用户所有的游戏状态 + /// + public List PlayGameUserInfos { get; set; } + + /// + /// 在线人数 + /// + public List OnlineUser { get; set; } + + /// + /// 用户游戏状态统计 + /// + public Dictionary PlayGameStatusStatistics() => PlayGameUserInfos.GroupBy(it => it.GameStatus).ToDictionary(it => it.Key, it => it.Count()); + + /// + /// 今日注册人数 + /// + public int TodayRegisteredUsers { get; set; } + + /// + /// 今日登录人数 + /// + public int TodayLoggedInUsers { get; set; } + + /// + /// 当前在线人数 + /// + public int CurrentOnlineUsers { get; set; } + + /// + /// 当前玩游戏人数 + /// + public int CurrentPlayingUsers { get; set; } + + /// + /// 当前排队人数 + /// + public int CurrentQueuedUsers { get; set; } + + /// + /// 今日意向订单 + /// + public int TodayIntendedOrders { get; set; } + + /// + /// 今日支付订单 + /// + public int TodayPaidOrders { get; set; } + + /// + /// 今日充值金额 + /// + public decimal TodayRechargeAmount { get; set; } +}