diff --git a/src/CloudGaming/Api/CloudGaming.ExtApi/Controllers/CacheController.cs b/src/CloudGaming/Api/CloudGaming.ExtApi/Controllers/CacheController.cs
new file mode 100644
index 0000000..8e91404
--- /dev/null
+++ b/src/CloudGaming/Api/CloudGaming.ExtApi/Controllers/CacheController.cs
@@ -0,0 +1,44 @@
+using CloudGaming.Code.Config;
+using CloudGaming.ExtApi.Base;
+
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+
+using System.Text;
+
+namespace CloudGaming.ExtApi.Controllers
+{
+
+ ///
+ /// 缓存管理
+ ///
+ public class CacheController : CloudGamingControllerBase
+ {
+ public CacheController(IServiceProvider _serviceProvider) : base(_serviceProvider)
+ {
+ }
+
+ ///
+ /// 清除缓存
+ ///
+ ///
+ [HttpGet]
+ public async Task ClearAllCacheData()
+ {
+ var outputStream = Response.Body;
+
+ Response.ContentType = "text/plain"; // 设置响应内容类型
+ Response.StatusCode = 200; // 设置状态码
+ await foreach (var item in new AppConfigBLL(ServiceProvider).ClearAllCacheData())
+ {
+ if (item == null)
+ {
+ continue;
+ }
+ await outputStream.WriteAsync(Encoding.UTF8.GetBytes(item));
+ await outputStream.FlushAsync();
+ }
+ return new EmptyResult();
+ }
+ }
+}
diff --git a/src/CloudGaming/Api/CloudGaming.ExtApi/Controllers/MonitorController.cs b/src/CloudGaming/Api/CloudGaming.ExtApi/Controllers/MonitorController.cs
index a656c6d..5c589e1 100644
--- a/src/CloudGaming/Api/CloudGaming.ExtApi/Controllers/MonitorController.cs
+++ b/src/CloudGaming/Api/CloudGaming.ExtApi/Controllers/MonitorController.cs
@@ -49,4 +49,5 @@ public class MonitorController : CloudGamingControllerBase
return await new MonitorBLL(ServiceProvider).GetAppMonitorHourAsync(startTimeStamp, endTimeStamp);
}
+
}
diff --git a/src/CloudGaming/Api/CloudGaming.ExtApi/Program.cs b/src/CloudGaming/Api/CloudGaming.ExtApi/Program.cs
index 6167435..16bb5b6 100644
--- a/src/CloudGaming/Api/CloudGaming.ExtApi/Program.cs
+++ b/src/CloudGaming/Api/CloudGaming.ExtApi/Program.cs
@@ -1,10 +1,14 @@
+using CloudGaming.AppConfigModel;
using CloudGaming.Code.AppExtend;
using CloudGaming.Code.DataAccess.MultiTenantUtil;
using CloudGaming.Code.Extend;
using CloudGaming.Code.Filter;
using CloudGaming.Code.Game;
using CloudGaming.Code.Monitor;
+using CloudGaming.DtoModel;
using CloudGaming.GameModel.Db.Db_Ext;
+using CloudGaming.GameModel.Db.Db_Game;
+using CloudGaming.Model.DbSqlServer.Db_User;
using HuanMeng.DotNetCore.CustomExtension;
using HuanMeng.DotNetCore.MiddlewareExtend;
@@ -44,16 +48,10 @@ builder.Services.AddSingleton(typeof(ILogger), serviceProvi
#endregion
#region automap
var mapperDomain = AppDomain.CurrentDomain.GetAssemblies().Where(it => it.FullName.Contains("HuanMeng") || it.FullName.Contains("CloudGaming.")).ToList();
-Type type = typeof(T_App_Config);
-if (type != null)
-{
- Assembly assembly = Assembly.GetAssembly(type);
- if (!mapperDomain.Any(it => it.FullName == assembly.FullName))
- {
- mapperDomain.Add(assembly);
- }
-}
-
+AddAssembly(mapperDomain, typeof(T_App_Config));
+AddAssembly(mapperDomain,typeof(AppConfig));
+AddAssembly(mapperDomain, typeof(AppConfigCache));
+AddAssembly(mapperDomain, typeof(T_User));
builder.Services.AddAutoMapper(mapperDomain);
#endregion
#region 添加跨域
@@ -140,3 +138,16 @@ app.UseAppRequest("ext");
#endregion
#endregion
app.Run();
+
+void AddAssembly(List mapperDomain, Type type)
+{
+
+ if (type != null)
+ {
+ Assembly assembly = Assembly.GetAssembly(type);
+ if (!mapperDomain.Any(it => it.FullName == assembly.FullName))
+ {
+ mapperDomain.Add(assembly);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/CloudGaming/Code/CloudGaming.Code/AppExtend/AppConfigurationExtend.cs b/src/CloudGaming/Code/CloudGaming.Code/AppExtend/AppConfigurationExtend.cs
index f4bcfe6..a092db9 100644
--- a/src/CloudGaming/Code/CloudGaming.Code/AppExtend/AppConfigurationExtend.cs
+++ b/src/CloudGaming/Code/CloudGaming.Code/AppExtend/AppConfigurationExtend.cs
@@ -246,6 +246,7 @@ namespace CloudGaming.Code.AppExtend
newAppConfig.PrivacyAgreement = appConfig.PrivacyAgreement;
newAppConfig.UserAgreement = appConfig.UserAgreement;
newAppConfig.LanguageRequestUrl = appConfig.LanguageRequestUrl;
+ newAppConfig.CacheRequestUrls = appConfig.CacheRequestUrls;
return newAppConfig;
}
diff --git a/src/CloudGaming/Code/CloudGaming.Code/Cache/Special/AppConfigEntityCache.cs b/src/CloudGaming/Code/CloudGaming.Code/Cache/Special/AppConfigEntityCache.cs
index 55a7423..dfcbe18 100644
--- a/src/CloudGaming/Code/CloudGaming.Code/Cache/Special/AppConfigEntityCache.cs
+++ b/src/CloudGaming/Code/CloudGaming.Code/Cache/Special/AppConfigEntityCache.cs
@@ -25,13 +25,13 @@ namespace CloudGaming.Code.Cache.Special
///
///
///
- public class AppConfigEntityCache(DAO dao, IDatabase database, IMapper mapper, AppConfig appConfig) : RedisDataEntityCache(database, 0)
+ public class AppConfigEntityCache(DAO dao, IDatabase database, IMapper mapper, AppConfig appConfig) : RedisDataEntityCache(database, 0, "系统配置")
{
public override string key => $"cache:appconfig:list";
public override List GetDataList()
{
- var list = dao.DaoExt.Context.T_App_Config.Where(it => it.ConfigType !=(int)AppConfigType.协议配置).ToList();
+ var list = dao.DaoExt.Context.T_App_Config.Where(it => it.ConfigType != (int)AppConfigType.协议配置).ToList();
var appList = mapper.Map>(list);
return appList;
diff --git a/src/CloudGaming/Code/CloudGaming.Code/Cache/Special/GameEntityCache.cs b/src/CloudGaming/Code/CloudGaming.Code/Cache/Special/GameEntityCache.cs
index 26f6dc3..f207d42 100644
--- a/src/CloudGaming/Code/CloudGaming.Code/Cache/Special/GameEntityCache.cs
+++ b/src/CloudGaming/Code/CloudGaming.Code/Cache/Special/GameEntityCache.cs
@@ -120,7 +120,7 @@ namespace CloudGaming.Code.Cache.Special
.Select(entry => JsonConvert.DeserializeObject(entry.Value))
.ToList();
- MemoryCacheHelper.SetCache(key, list, 10);
+ MemoryCacheHelper.SetCache(key, list, 60 * 60 * 12);
_dataList = list;
return _dataList;
}
@@ -135,8 +135,8 @@ namespace CloudGaming.Code.Cache.Special
.Select(info => new HashEntry($"gameInfo:{info.GameId}", JsonConvert.SerializeObject(info)))
.ToArray();
database.HashSet(RedisKey, serializedGameInfos);
-
- MemoryCacheHelper.SetCache(key, tempDataList, 60 * 60);
+ database.StringSet($"time:{RedisKey.Replace(":", ".")}", $"刷新游戏缓存时间{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}");
+ MemoryCacheHelper.SetCache(key, tempDataList, 60 * 60 * 12);
_dataList = tempDataList;
database.KeyDelete(locaKey);
return _dataList;
@@ -216,26 +216,20 @@ namespace CloudGaming.Code.Cache.Special
public override bool ClearData()
{
- lock (GameEntityCacheLock)
- {
- database.KeyDelete(RedisKey);
- MemoryCacheHelper.DelCache(key);
- _dataList = null;
- gameInfoDic = null;
- }
+ database.KeyDelete(RedisKey);
+ MemoryCacheHelper.DelCache(key);
+ _dataList = null;
+ gameInfoDic = null;
return true;
}
public override void ReloadData()
{
- lock (lockObj)
- {
- database.KeyDelete(RedisKey);
- MemoryCacheHelper.DelCache(key);
- _dataList = null;
- gameInfoDic = null;
- var x = DataList;
- }
+ database.KeyDelete(RedisKey);
+ MemoryCacheHelper.DelCache(key);
+ _dataList = null;
+ gameInfoDic = null;
+ var x = DataList;
}
public bool ClearLocalData()
diff --git a/src/CloudGaming/Code/CloudGaming.Code/Cache/Special/ImageEntityCache.cs b/src/CloudGaming/Code/CloudGaming.Code/Cache/Special/ImageEntityCache.cs
index 68b6050..774b840 100644
--- a/src/CloudGaming/Code/CloudGaming.Code/Cache/Special/ImageEntityCache.cs
+++ b/src/CloudGaming/Code/CloudGaming.Code/Cache/Special/ImageEntityCache.cs
@@ -199,12 +199,86 @@ public class ImageEntityCache : ICacheClearData, ICacheReloadData, ICacheClearLo
database.StringSet($"{redisKey}:language:{_language}", d);
}
database.StringSet($"{redisKey}:language", languages);
-
+ database.StringSet($"time:{redisKey.Replace(":", ".")}", $"刷新图片缓存时间{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}");
#endregion
return;
}
+ public void LoadRedisDatabase()
+ {
+
+ var data = new ConcurrentDictionary>();
+ var images = dao.DaoExt.Context.T_App_Image
+ .Where(it => !string.IsNullOrEmpty(it.Url))
+ .AsNoTracking()
+ .Select(it => new { it.ImageId, it.Language, it.Url })
+ .ToList();
+ // 设置默认语言
+ if (string.IsNullOrEmpty(appConfig.DefaultLanguage))
+ {
+ appConfig.DefaultLanguage = "zh";
+ }
+ // 创建默认语言的图像字典
+ var defaultImage = images
+ .Where(it => it.Language == appConfig.DefaultLanguage)
+ .GroupBy(it => it.ImageId)
+ .ToDictionary(group => group.Key, group => appConfig.AliyunConfig.ImagePrefix + group.Last().Url);
+ if (defaultImage == null)
+ {
+ defaultImage = new Dictionary();
+ }
+ foreach (var image in images)
+ {
+ if (string.IsNullOrEmpty(image.Url))
+ {
+ continue;
+ }
+ var languageCache = data.GetOrAdd(image.Language, _ => new ConcurrentDictionary());
+ var url = string.Empty;
+ if (image.Url.StartsWith("http://") || image.Url.StartsWith("https://"))
+ {
+ url = $"{image.Url}";
+ }
+ else
+ {
+ url = $"{appConfig.AliyunConfig.ImagePrefix}{image.Url}";
+ }
+ languageCache[image.ImageId] = url;
+ // 如果默认图像字典中没有此ImageId,加入默认图像字典
+ if (!defaultImage.ContainsKey(image.ImageId))
+ {
+ defaultImage[image.ImageId] = url;
+ }
+ }
+ #region 保存默认图片
+ var defaultLanguageCache = new ConcurrentDictionary(defaultImage);
+ foreach (var kv in defaultLanguageCache)
+ {
+ database.StringSet($"{redisKey}:default:{kv.Key}", kv.Value);
+ }
+ //data.TryAdd("default", defaultLanguageCache);
+ #endregion
+ #region 保存其他图片
+ foreach (var _language in languages)
+ {
+ var mKey = $"{appConfig.Identifier}:App:Image:{_language}";
+ if (!data.TryGetValue(_language, out var d))
+ {
+ d = defaultLanguageCache;
+ }
+ foreach (var kv in d)
+ {
+ database.StringSet($"{redisKey}:{_language}:{kv.Key}", kv.Value);
+ }
+ database.StringSet($"{redisKey}:language:{_language}", d);
+ }
+ database.StringSet($"{redisKey}:language", languages);
+ database.StringSet($"time:{redisKey.Replace(":", ".")}", $"刷新图片缓存时间{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}");
+ #endregion
+ return;
+ }
+
public bool ClearData()
{
diff --git a/src/CloudGaming/Code/CloudGaming.Code/Cache/Special/ProductCacheEntityCache.cs b/src/CloudGaming/Code/CloudGaming.Code/Cache/Special/ProductCacheEntityCache.cs
index 85de7c5..add362e 100644
--- a/src/CloudGaming/Code/CloudGaming.Code/Cache/Special/ProductCacheEntityCache.cs
+++ b/src/CloudGaming/Code/CloudGaming.Code/Cache/Special/ProductCacheEntityCache.cs
@@ -23,7 +23,7 @@ namespace CloudGaming.Code.Cache.Special;
///
///
///
-public class ProductCacheEntityCache(DAO dao, IDatabase database, IMapper mapper) : RedisDataEntityCache(database, 60 * 60 * 12)
+public class ProductCacheEntityCache(DAO dao, IDatabase database, IMapper mapper) : RedisDataEntityCache(database, 60 * 60 * 12,"产品")
{
public override string key => "cache:Product:list";
diff --git a/src/CloudGaming/Code/CloudGaming.Code/Cache/Special/RedemptionCodeEntityCache.cs b/src/CloudGaming/Code/CloudGaming.Code/Cache/Special/RedemptionCodeEntityCache.cs
index d8f2310..83fd406 100644
--- a/src/CloudGaming/Code/CloudGaming.Code/Cache/Special/RedemptionCodeEntityCache.cs
+++ b/src/CloudGaming/Code/CloudGaming.Code/Cache/Special/RedemptionCodeEntityCache.cs
@@ -22,7 +22,7 @@ namespace CloudGaming.Code.Cache.Special;
///
///
///
-public class RedemptionCodeEntityCache(DAO dao, IDatabase database, IMapper mapper) : RedisDataEntityCache(database,60 * 60 * 1)
+public class RedemptionCodeEntityCache(DAO dao, IDatabase database, IMapper mapper) : RedisDataEntityCache(database,60 * 60 * 1, "兑换码")
{
public override List GetDataList()
{
diff --git a/src/CloudGaming/Code/CloudGaming.Code/Cache/Special/SevenDayEntityCache.cs b/src/CloudGaming/Code/CloudGaming.Code/Cache/Special/SevenDayEntityCache.cs
index 11eaea9..c6fb224 100644
--- a/src/CloudGaming/Code/CloudGaming.Code/Cache/Special/SevenDayEntityCache.cs
+++ b/src/CloudGaming/Code/CloudGaming.Code/Cache/Special/SevenDayEntityCache.cs
@@ -22,7 +22,7 @@ namespace CloudGaming.Code.Cache.Special;
///
///
///
-public class SevenDayEntityCache(DAO dao, IDatabase database, IMapper mapper) : RedisDataEntityCache(database, 60 * 60 * 24 * 7)
+public class SevenDayEntityCache(DAO dao, IDatabase database, IMapper mapper) : RedisDataEntityCache(database, 60 * 60 * 24 * 7, "七天签到")
{
public override List GetDataList()
{
diff --git a/src/CloudGaming/Code/CloudGaming.Code/Config/AppConfigBLL.cs b/src/CloudGaming/Code/CloudGaming.Code/Config/AppConfigBLL.cs
index bf135d7..e70b21d 100644
--- a/src/CloudGaming/Code/CloudGaming.Code/Config/AppConfigBLL.cs
+++ b/src/CloudGaming/Code/CloudGaming.Code/Config/AppConfigBLL.cs
@@ -1,12 +1,20 @@
+using Azure;
+
+using CloudGaming.AppConfigModel;
+using CloudGaming.Code.AppExtend;
using CloudGaming.Code.Cache;
using CloudGaming.DtoModel;
+using StackExchange.Redis;
+
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
+using static SKIT.FlurlHttpClient.Wechat.TenpayV3.Models.CreateNewTaxControlFapiaoApplicationRequest.Types.Fapiao.Types;
+
namespace CloudGaming.Code.Config
{
///
@@ -68,5 +76,86 @@ namespace CloudGaming.Code.Config
return true;
}
+ ///
+ /// 清除缓存
+ ///
+ ///
+ ///
+ /// 清除缓存
+ ///
+ ///
+ public async IAsyncEnumerable ClearAllCacheData()
+ {
+ // 开始总耗时计时
+ var swAll = Stopwatch.StartNew();
+
+ // 删除应用配置缓存
+ var delAppConfig = Stopwatch.StartNew();
+ var keysDeleted = (int)await RedisCache.KeysDeleteds("App:Config:*");
+ delAppConfig.Stop();
+ yield return $"删除app配置:{keysDeleted}, 耗时==》{delAppConfig.ElapsedMilliseconds.ToString("0.##")}毫秒";
+
+ // 删除API接口缓存
+ var apiCache = Stopwatch.StartNew();
+ var keysDeleted1 = (int)await RedisCache.KeysDeleteds("cache:api:*");
+ apiCache.Stop();
+ yield return $"删除api接口缓存:{keysDeleted1}, 耗时==》{apiCache.ElapsedMilliseconds.ToString("0.##")}毫秒";
+
+ // 删除图片缓存
+ var imageCache = Stopwatch.StartNew();
+ var imageDel = (int)await RedisCache.KeysDeleteds("cache:Image:*");
+ imageCache.Stop();
+ yield return $"删除图片缓存:{imageDel}, 耗时==》{imageCache.ElapsedMilliseconds.ToString("0.##")}毫秒";
+
+ // 重新加载缓存
+ var reloadCache = Stopwatch.StartNew();
+ Cache.AppImageCache.LoadRedisDatabase();
+ yield return $"重新加载图片缓存";
+ Cache.GameEntityCache.ReloadData();
+ yield return $"重新加载游戏缓存";
+ Cache.AppConfigCache.ReloadData();
+ yield return $"重新加载系统配置缓存";
+ Cache.ProductCacheEntityCache.ReloadData();
+ yield return $"重新加载产品缓存";
+ Cache.RedemptionCodeEntityCache.ReloadData();
+ yield return $"重新加载兑换码缓存";
+ Cache.SevenDayEntityCache.ReloadData();
+ yield return $"重新加载七天签到缓存";
+ reloadCache.Stop();
+ yield return $"全部重新加载缓存耗时==》{reloadCache.ElapsedMilliseconds.ToString("0.##")}毫秒";
+
+ // 清除本地缓存
+ var clearLocalCache = Stopwatch.StartNew();
+ ClearCacheData();
+ clearLocalCache.Stop();
+ yield return $"清除本地缓存, 耗时==》{clearLocalCache.ElapsedMilliseconds.ToString("0.##")}毫秒";
+
+ // 清除网络缓存
+ var clearNetworkCache = Stopwatch.StartNew();
+ var urls = AppConfig.CacheRequestUrls ?? new List();
+ foreach (var url in urls)
+ {
+ string resp = string.Empty;
+ try
+ {
+ var client = HttpClientFactory.CreateClient();
+ var data = await client.GetAsync(url);
+ resp = $"清除网络缓存{url}===》{data}";
+ }
+ catch (Exception ex)
+ {
+ resp = $"清除网络缓存{url}失败===》{ex.Message}";
+ }
+ yield return resp;
+ }
+ clearNetworkCache.Stop();
+ yield return $"清除网络缓存耗时==》{clearNetworkCache.ElapsedMilliseconds.ToString("0.##")}毫秒";
+
+ // 停止总耗时计时
+ swAll.Stop();
+ yield return $"清除结束, 总耗时==》{swAll.ElapsedMilliseconds.ToString("0.##")}毫秒";
+ }
+
+
}
}
diff --git a/src/CloudGaming/Model/CloudGaming.AppConfigModel/AppConfig.cs b/src/CloudGaming/Model/CloudGaming.AppConfigModel/AppConfig.cs
index 98bed38..3db9293 100644
--- a/src/CloudGaming/Model/CloudGaming.AppConfigModel/AppConfig.cs
+++ b/src/CloudGaming/Model/CloudGaming.AppConfigModel/AppConfig.cs
@@ -89,6 +89,11 @@ namespace CloudGaming.AppConfigModel
/// 多语言列表请求地址
///
public string LanguageRequestUrl { get; set; }
+
+ ///
+ /// 清除缓存接口
+ ///
+ public List CacheRequestUrls { get; set; }
///
/// 获取数据库连接字符串
///
diff --git a/src/CloudGaming/Utile/HuanMeng.DotNetCore/CacheHelper/CommonDataEntityCache.cs b/src/CloudGaming/Utile/HuanMeng.DotNetCore/CacheHelper/CommonDataEntityCache.cs
index 4a87e45..d4f5da4 100644
--- a/src/CloudGaming/Utile/HuanMeng.DotNetCore/CacheHelper/CommonDataEntityCache.cs
+++ b/src/CloudGaming/Utile/HuanMeng.DotNetCore/CacheHelper/CommonDataEntityCache.cs
@@ -117,11 +117,14 @@ public abstract class RedisDataEntityCache : CommonDataEntityCache, ICache
///
protected int cacheTime;
- protected RedisDataEntityCache(IDatabase database,int cacheTime = 36000) : base(new object(), cacheTime)
+ private string name;
+
+ protected RedisDataEntityCache(IDatabase database, int cacheTime = 36000, string name = "") : base(new object(), cacheTime)
{
this.lockObj = lockObj;
this.cacheTime = cacheTime;
this.database = database;
+ this.name = name;
}
public int index = 0;
@@ -212,6 +215,8 @@ public abstract class RedisDataEntityCache : CommonDataEntityCache, ICache
}
_dataList = tempDataList;
database.KeyDeleteAsync($"lock:{key}").Wait();
+ database.StringSet($"time:{key.Replace(":", ".")}", $"刷新{name}缓存时间{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}");
+
}
}
diff --git a/src/CloudGaming/Utile/HuanMeng.DotNetCore/Redis/RedisConnection.cs b/src/CloudGaming/Utile/HuanMeng.DotNetCore/Redis/RedisConnection.cs
index 22ab78e..54339b2 100644
--- a/src/CloudGaming/Utile/HuanMeng.DotNetCore/Redis/RedisConnection.cs
+++ b/src/CloudGaming/Utile/HuanMeng.DotNetCore/Redis/RedisConnection.cs
@@ -132,6 +132,29 @@ namespace HuanMeng.DotNetCore.Redis
return database.StringSet(key, value, TimeSpan.FromSeconds(time), when: When.NotExists);
}
+ ///
+ /// 删除key
+ ///
+ ///
+ ///
+ ///
+ public static async Task KeysDeleteds(this IDatabase database, string key)
+ {
+
+ string luaScript = @"
+local keys = redis.call('KEYS', ARGV[1])
+if next(keys) ~= nil then
+ return redis.call('DEL', unpack(keys))
+else
+ return 0
+end
+";
+
+ var keysDeleted = (int)await (database.ScriptEvaluateAsync(luaScript, values: new RedisValue[] { key }));
+ return keysDeleted;
+ }
+
+
///
/// 获取一个key的对象
///