diff --git a/src/CloudGaming/Api/CloudGaming.Api/Controllers/AppController.cs b/src/CloudGaming/Api/CloudGaming.Api/Controllers/AppController.cs index a24a08c..514ed7d 100644 --- a/src/CloudGaming/Api/CloudGaming.Api/Controllers/AppController.cs +++ b/src/CloudGaming/Api/CloudGaming.Api/Controllers/AppController.cs @@ -1,4 +1,5 @@ using CloudGaming.Api.Base; +using CloudGaming.DtoModel; using CloudGaming.GameModel.Db.Db_Ext; using HuanMeng.DotNetCore.Base; @@ -22,9 +23,11 @@ namespace CloudGaming.Api.Controllers /// /// [HttpGet] - public async Task GetAppConfigAsync() + public async Task GetAppConfigAsync() { - return new { test = "测试", Data = new { txt = "内部数据" } }; + AppConfigDto appConfigDto = new AppConfigDto(); + appConfigDto.AppConfigExtend = new AppConfigExtend(); + return appConfigDto; } /// diff --git a/src/CloudGaming/Api/CloudGaming.Api/appsettings.json b/src/CloudGaming/Api/CloudGaming.Api/appsettings.json index 6be6211..9d8e2c3 100644 --- a/src/CloudGaming/Api/CloudGaming.Api/appsettings.json +++ b/src/CloudGaming/Api/CloudGaming.Api/appsettings.json @@ -69,6 +69,15 @@ "refreshTokenExpiration": 10100 }, + "AgileConfig": { + "appId": "CloudGaming", + "secret": "95BB717C61D1ECB0E9FB82C932CC77FF", + "nodes": "http://124.220.55.158:94", //多个节点使用逗号分隔 + "url": "http://124.220.55.158:94", + "env": "DEV", + "UserName": "admin", + "Password": "dbt@com@1234" + }, //服务器配置 "Kestrel": { "Endpoints": { diff --git a/src/CloudGaming/Code/CloudGaming.Code/AppExtend/AppConfigurationExtend.cs b/src/CloudGaming/Code/CloudGaming.Code/AppExtend/AppConfigurationExtend.cs index 8e5d079..b96dbd1 100644 --- a/src/CloudGaming/Code/CloudGaming.Code/AppExtend/AppConfigurationExtend.cs +++ b/src/CloudGaming/Code/CloudGaming.Code/AppExtend/AppConfigurationExtend.cs @@ -1,5 +1,9 @@ +using AgileConfig.Client; + using CloudGaming.Code.DataAccess.MultiTenantUtil; +using HuanMeng.DotNetCore.CacheHelper; + using System.Collections.Concurrent; using System.Collections.Frozen; @@ -44,6 +48,31 @@ namespace CloudGaming.Code.AppExtend return AppConfigs.FirstOrDefault().Value; } + /// + /// + /// + /// + public static void ConfigClient_ConfigChanged(ConfigReloadedArgs args) + { + + if (args.OldConfigs.TryGetValue("Version", out var vresion) && args.NewConfigs.TryGetValue("Version", out var newVersion)) + { + if (vresion != newVersion) + { + MemoryCacheHelper.cache.Clear(); + } + } + VerifyTenant(args); + //if (VerifyTenant(args, "Payment:WeChatConfig")) + //{ + // PaymentExtend.AddWeChat(ConfigurationManager); + //} + //if (VerifyTenant(args, "Payment:AlipayConfig")) + //{ + // PaymentExtend.AddAlipay(ConfigurationManager); + + //} + } /// @@ -51,12 +80,11 @@ namespace CloudGaming.Code.AppExtend /// /// /// - public static IHostApplicationBuilder AddAppConfigClient(this IHostApplicationBuilder builder) + public static IHostApplicationBuilder AddAppConfigClient(this WebApplicationBuilder builder) { - //hostBuilder. - //builder..UseAgileConfig(configClient, ConfigClient_ConfigChanged); - //AppConfigClient = configClient; + var configClient = new ConfigClient(builder.Configuration); + builder.Host.UseAgileConfig(configClient, ConfigClient_ConfigChanged); ConfigurationManager = builder.Configuration; AppConfigInit(builder.Configuration); builder.Services.AddScoped(); @@ -137,6 +165,41 @@ namespace CloudGaming.Code.AppExtend return newAppConfig; } + /// + /// 验证多租户 + /// + /// + private static bool VerifyTenant(ConfigReloadedArgs args, string key) + { + var newTenant = args.NewConfigs.Where(it => it.Key.Contains(key)).ToDictionary(); + var oldTenant = args.OldConfigs.Where(it => it.Key.Contains(key)).ToDictionary(); + bool areEqual = newTenant.Count == oldTenant.Count && + !newTenant.Except(oldTenant).Any(); + if (!areEqual) + { + //更新缓存 + //AppConfigInit(ConfigurationManager); + return true; + } + return false; + } + /// + /// 验证多租户 + /// + /// + private static void VerifyTenant(ConfigReloadedArgs args) + { + var newTenant = args.NewConfigs.Where(it => it.Key.Contains("Tenants")).ToDictionary(); + var oldTenant = args.OldConfigs.Where(it => it.Key.Contains("Tenants")).ToDictionary(); + bool areEqual = newTenant.Count == oldTenant.Count && + !newTenant.Except(oldTenant).Any(); + if (!areEqual) + { + //更新缓存 + AppConfigInit(ConfigurationManager); + } + + } /// /// 初始化租户数据 @@ -144,7 +207,7 @@ namespace CloudGaming.Code.AppExtend /// private static void AppConfigInit(IConfigurationManager configurationManager) { - var tenants = configurationManager.GetSection("Tenant").Get>(); + var tenants = configurationManager.GetSection("Tenants").Get>(); if (tenants != null) { ConcurrentDictionary _AppConfigs = new ConcurrentDictionary(); diff --git a/src/CloudGaming/Code/CloudGaming.Code/AppExtend/CustomResultFilter.cs b/src/CloudGaming/Code/CloudGaming.Code/AppExtend/CustomResultFilter.cs index fc27fcb..b7070e8 100644 --- a/src/CloudGaming/Code/CloudGaming.Code/AppExtend/CustomResultFilter.cs +++ b/src/CloudGaming/Code/CloudGaming.Code/AppExtend/CustomResultFilter.cs @@ -1,3 +1,5 @@ +using HuanMeng.DotNetCore.AttributeExtend; + using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; @@ -36,11 +38,90 @@ namespace CloudGaming.Code.AppExtend { } + FindImagesAttributes(objectResult.Value); + // var responseObject = objectResult.Value; + // var membersWithImagesAttribute = responseObject.GetType() + //.GetMembers(BindingFlags.Public | BindingFlags.Instance) + //.Where(m => m.GetCustomAttribute() != null); + // foreach (var member in membersWithImagesAttribute) + // { + // var imagesAttribute = member.GetCustomAttribute(); + // Console.WriteLine($"带有 [Images] 特性的成员:{member.Name}"); + // Console.WriteLine($"FieldName 属性值:{imagesAttribute?.FieldName}"); + // } // 递归处理返回对象的所有属性并打印路径 ProcessObjectProperties(objectResult.Value, user, language, path); } } + private void FindImagesAttributes(object obj) + { + if (obj == null) return; + + // 使用反射获取对象的所有公共实例属性和字段 + var membersWithImagesAttribute = obj.GetType() + .GetMembers(BindingFlags.Public | BindingFlags.Instance) + .Where(m => m is PropertyInfo || m is FieldInfo); + + foreach (var member in membersWithImagesAttribute) + { + // 获取并输出带有 [Images] 特性的属性或字段 + var imagesAttribute = member.GetCustomAttribute(); + if (imagesAttribute != null) + { + Console.WriteLine($"带有 [Images] 特性的成员:{member.Name}"); + Console.WriteLine($"FieldName 属性值:{imagesAttribute.FieldName}"); + + object value = GetMemberValue(member, obj); + Console.WriteLine($"成员值:{value}"); + } + + // 获取成员值 + var memberValue = GetMemberValue(member, obj); + + // 如果成员是 IEnumerable(集合类型),递归处理每个元素 + if (memberValue is IEnumerable enumerableValue && memberValue.GetType() != typeof(string)) + { + foreach (var item in enumerableValue) + { + if (item != null && !IsSimpleType(item.GetType())) + { + FindImagesAttributes(item); + } + } + } + // 如果成员是非集合的复杂类型,递归检查其内部成员 + else if (memberValue != null && !IsSimpleType(memberValue.GetType())) + { + FindImagesAttributes(memberValue); + } + } + } + + private object GetMemberValue(MemberInfo member, object obj) + { + try + { + return member switch + { + PropertyInfo property when property.GetMethod?.IsStatic == false => property.GetValue(obj), + FieldInfo field when !field.IsStatic => field.GetValue(obj), + _ => null + }; + } + catch (TargetParameterCountException ex) + { + Console.WriteLine($"Error retrieving value for {member.Name}: {ex.Message}"); + return null; + } + } + + private bool IsSimpleType(Type type) + { + return type.IsPrimitive || type.IsEnum || type == typeof(string) || type == typeof(decimal); + } + + public void OnResultExecuted(ResultExecutedContext context) { // 可在执行完结果后处理其他逻辑 diff --git a/src/CloudGaming/Code/CloudGaming.Code/CloudGaming.Code.csproj b/src/CloudGaming/Code/CloudGaming.Code/CloudGaming.Code.csproj index b0db308..24f5cb2 100644 --- a/src/CloudGaming/Code/CloudGaming.Code/CloudGaming.Code.csproj +++ b/src/CloudGaming/Code/CloudGaming.Code/CloudGaming.Code.csproj @@ -9,6 +9,7 @@ + diff --git a/src/CloudGaming/Model/CloudGaming.DtoModel/AppConfigDto.cs b/src/CloudGaming/Model/CloudGaming.DtoModel/AppConfigDto.cs new file mode 100644 index 0000000..02d3dab --- /dev/null +++ b/src/CloudGaming/Model/CloudGaming.DtoModel/AppConfigDto.cs @@ -0,0 +1,53 @@ +using HuanMeng.DotNetCore.AttributeExtend; + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudGaming.DtoModel; + +/// +/// +/// +public class AppConfigDto +{ + /// + /// 是否版本审核中 + /// + public bool IsChecking { get; set; } + + /// + /// 版本审核中可玩游戏(在谷歌包的审核模式下可以玩的游戏列表) + /// + public List CheckingGames = new List(); + + /// + /// 是否开启实名认证 + /// + public bool IsAuthRealName { get; set; } + + /// + /// 是否是高延迟地区 + /// + public bool HighDelay { get; set; } + + /// + /// 开屏图 + /// + [Images] + public int OpenImage { get; set; } + + + public AppConfigExtend AppConfigExtend { get; set; } +} + +public class AppConfigExtend +{ + /// + /// 开屏图 + /// + [Images] + public int TestImage { get; set; } +} diff --git a/src/CloudGaming/Model/CloudGaming.GameModel/Db/Db_Ext/CloudGamingCBTContext.cs b/src/CloudGaming/Model/CloudGaming.GameModel/Db/Db_Ext/CloudGamingCBTContext.cs index 47f9781..c0a28a3 100644 --- a/src/CloudGaming/Model/CloudGaming.GameModel/Db/Db_Ext/CloudGamingCBTContext.cs +++ b/src/CloudGaming/Model/CloudGaming.GameModel/Db/Db_Ext/CloudGamingCBTContext.cs @@ -67,9 +67,12 @@ public partial class CloudGamingCBTContext : DbContext entity.Property(e => e.BossId) .HasMaxLength(200) + .HasComment("渠道号") .UseCollation("Chinese_PRC_CI_AS"); - entity.Property(e => e.ConfigStr) - .HasMaxLength(2000) + entity.Property(e => e.ConfigId).HasComment("配置值"); + entity.Property(e => e.ConfigType).HasComment("配置类型"); + entity.Property(e => e.ConfigValue) + .HasComment("配置值") .UseCollation("Chinese_PRC_CI_AS"); entity.Property(e => e.Continent) .HasMaxLength(200) @@ -79,18 +82,26 @@ public partial class CloudGamingCBTContext : DbContext .HasMaxLength(200) .HasComment("国家 例:中国") .UseCollation("Chinese_PRC_CI_AS"); - entity.Property(e => e.CreatTime).HasColumnType("datetime"); + entity.Property(e => e.CreatTime) + .HasComment("创建时间") + .HasColumnType("datetime"); entity.Property(e => e.Desc) - .HasMaxLength(2000) + .HasComment("备注") + .UseCollation("Chinese_PRC_CI_AS"); + entity.Property(e => e.ExtJson).HasComment("扩展信息"); + entity.Property(e => e.IsShow).HasComment("是否启用"); + entity.Property(e => e.Name) + .HasMaxLength(200) + .HasComment("配置名称") .UseCollation("Chinese_PRC_CI_AS"); entity.Property(e => e.Plat) .HasMaxLength(100) .IsUnicode(false) + .HasComment("平台。安卓还是苹果") .UseCollation("Chinese_PRC_CI_AS"); - entity.Property(e => e.ShowName) - .HasMaxLength(200) - .UseCollation("Chinese_PRC_CI_AS"); - entity.Property(e => e.UpdateTime).HasColumnType("datetime"); + entity.Property(e => e.UpdateTime) + .HasComment("修改时间") + .HasColumnType("datetime"); }); diff --git a/src/CloudGaming/Model/CloudGaming.GameModel/Db/Db_Ext/T_App_Config.cs b/src/CloudGaming/Model/CloudGaming.GameModel/Db/Db_Ext/T_App_Config.cs index 22bb558..e30fcd0 100644 --- a/src/CloudGaming/Model/CloudGaming.GameModel/Db/Db_Ext/T_App_Config.cs +++ b/src/CloudGaming/Model/CloudGaming.GameModel/Db/Db_Ext/T_App_Config.cs @@ -11,28 +11,44 @@ public partial class T_App_Config public virtual int Id { get; set; } - public virtual int? ConfigType { get; set; } + /// + /// 配置类型 + /// + public virtual int ConfigType { get; set; } - public virtual int? ConfigId { get; set; } + /// + /// 配置值 + /// + public virtual int ConfigId { get; set; } - public virtual bool? IsShow { get; set; } - - public virtual string? ShowName { get; set; } + /// + /// 是否启用 + /// + public virtual bool IsShow { get; set; } + /// + /// 备注 + /// public virtual string? Desc { get; set; } + /// + /// 修改时间 + /// public virtual DateTime? UpdateTime { get; set; } + /// + /// 创建时间 + /// public virtual DateTime? CreatTime { get; set; } - public virtual int? ConfigNum { get; set; } - - public virtual int? ConfigNum2 { get; set; } - - public virtual string? ConfigStr { get; set; } - + /// + /// 渠道号 + /// public virtual string? BossId { get; set; } + /// + /// 平台。安卓还是苹果 + /// public virtual string? Plat { get; set; } /// @@ -44,4 +60,19 @@ public partial class T_App_Config /// 国家 例:中国 /// public virtual string? CountryName { get; set; } + + /// + /// 配置值 + /// + public virtual string? ConfigValue { get; set; } + + /// + /// 配置名称 + /// + public virtual string? Name { get; set; } + + /// + /// 扩展信息 + /// + public virtual string? ExtJson { get; set; } } diff --git a/src/CloudGaming/Utile/HuanMeng.DotNetCore/AttributeExtend/ImagesAttribute.cs b/src/CloudGaming/Utile/HuanMeng.DotNetCore/AttributeExtend/ImagesAttribute.cs new file mode 100644 index 0000000..1374f47 --- /dev/null +++ b/src/CloudGaming/Utile/HuanMeng.DotNetCore/AttributeExtend/ImagesAttribute.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace HuanMeng.DotNetCore.AttributeExtend; + +/// +/// +/// +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] +public class ImagesAttribute : Attribute +{ + + public string FieldName { get; set; } + /// + /// + /// + /// 生成字段名称 + // 构造函数,用于传递参数 + public ImagesAttribute(string fieldName = "") + { + this.FieldName = fieldName; + } +}