提交代码

This commit is contained in:
zpc 2024-12-10 03:41:21 +08:00
parent 898153e42f
commit efd6db3458
14 changed files with 282 additions and 35 deletions

View File

@ -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
{
/// <summary>
/// 缓存管理
/// </summary>
public class CacheController : CloudGamingControllerBase
{
public CacheController(IServiceProvider _serviceProvider) : base(_serviceProvider)
{
}
/// <summary>
/// 清除缓存
/// </summary>
/// <returns></returns>
[HttpGet]
public async Task<IActionResult> 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();
}
}
}

View File

@ -49,4 +49,5 @@ public class MonitorController : CloudGamingControllerBase
return await new MonitorBLL(ServiceProvider).GetAppMonitorHourAsync(startTimeStamp, endTimeStamp);
}
}

View File

@ -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<ExceptionMiddleware>), 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<Assembly> mapperDomain, Type type)
{
if (type != null)
{
Assembly assembly = Assembly.GetAssembly(type);
if (!mapperDomain.Any(it => it.FullName == assembly.FullName))
{
mapperDomain.Add(assembly);
}
}
}

View File

@ -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;
}

View File

@ -25,13 +25,13 @@ namespace CloudGaming.Code.Cache.Special
/// <param name="database"></param>
/// <param name="mapper"></param>
/// <param name="appConfig"></param>
public class AppConfigEntityCache(DAO dao, IDatabase database, IMapper mapper, AppConfig appConfig) : RedisDataEntityCache<AppConfigCache>(database, 0)
public class AppConfigEntityCache(DAO dao, IDatabase database, IMapper mapper, AppConfig appConfig) : RedisDataEntityCache<AppConfigCache>(database, 0, "系统配置")
{
public override string key => $"cache:appconfig:list";
public override List<AppConfigCache> 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<AppConfigCache>>(list);
return appList;

View File

@ -120,7 +120,7 @@ namespace CloudGaming.Code.Cache.Special
.Select(entry => JsonConvert.DeserializeObject<GameInfo>(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()

View File

@ -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<string, ConcurrentDictionary<int, string>>();
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<int, string>();
}
foreach (var image in images)
{
if (string.IsNullOrEmpty(image.Url))
{
continue;
}
var languageCache = data.GetOrAdd(image.Language, _ => new ConcurrentDictionary<int, string>());
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<int, string>(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()
{

View File

@ -23,7 +23,7 @@ namespace CloudGaming.Code.Cache.Special;
/// <param name="database"></param>
/// <param name="mapper"></param>
/// <param name="appConfig"></param>
public class ProductCacheEntityCache(DAO dao, IDatabase database, IMapper mapper) : RedisDataEntityCache<ProductCache>(database, 60 * 60 * 12)
public class ProductCacheEntityCache(DAO dao, IDatabase database, IMapper mapper) : RedisDataEntityCache<ProductCache>(database, 60 * 60 * 12,"产品")
{
public override string key => "cache:Product:list";

View File

@ -22,7 +22,7 @@ namespace CloudGaming.Code.Cache.Special;
/// <param name="dao"></param>
/// <param name="database"></param>
/// <param name="mapper"></param>
public class RedemptionCodeEntityCache(DAO dao, IDatabase database, IMapper mapper) : RedisDataEntityCache<RedemptionCodeCache>(database,60 * 60 * 1)
public class RedemptionCodeEntityCache(DAO dao, IDatabase database, IMapper mapper) : RedisDataEntityCache<RedemptionCodeCache>(database,60 * 60 * 1, "兑换码")
{
public override List<RedemptionCodeCache> GetDataList()
{

View File

@ -22,7 +22,7 @@ namespace CloudGaming.Code.Cache.Special;
/// <param name="dao"></param>
/// <param name="database"></param>
/// <param name="mapper"></param>
public class SevenDayEntityCache(DAO dao, IDatabase database, IMapper mapper) : RedisDataEntityCache<SevenDayCache>(database, 60 * 60 * 24 * 7)
public class SevenDayEntityCache(DAO dao, IDatabase database, IMapper mapper) : RedisDataEntityCache<SevenDayCache>(database, 60 * 60 * 24 * 7, "七天签到")
{
public override List<SevenDayCache> GetDataList()
{

View File

@ -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
{
/// <summary>
@ -68,5 +76,86 @@ namespace CloudGaming.Code.Config
return true;
}
/// <summary>
/// 清除缓存
/// </summary>
/// <returns></returns>
/// <summary>
/// 清除缓存
/// </summary>
/// <returns></returns>
public async IAsyncEnumerable<string> 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<string>();
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.##")}毫秒";
}
}
}

View File

@ -89,6 +89,11 @@ namespace CloudGaming.AppConfigModel
/// 多语言列表请求地址
/// </summary>
public string LanguageRequestUrl { get; set; }
/// <summary>
/// 清除缓存接口
/// </summary>
public List<string> CacheRequestUrls { get; set; }
/// <summary>
/// 获取数据库连接字符串
/// </summary>

View File

@ -117,11 +117,14 @@ public abstract class RedisDataEntityCache<T> : CommonDataEntityCache<T>, ICache
/// </summary>
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<T> : CommonDataEntityCache<T>, ICache
}
_dataList = tempDataList;
database.KeyDeleteAsync($"lock:{key}").Wait();
database.StringSet($"time:{key.Replace(":", ".")}", $"刷新{name}缓存时间{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}");
}
}

View File

@ -132,6 +132,29 @@ namespace HuanMeng.DotNetCore.Redis
return database.StringSet(key, value, TimeSpan.FromSeconds(time), when: When.NotExists);
}
/// <summary>
/// 删除key
/// </summary>
/// <param name="database"></param>
/// <param name="key"></param>
/// <returns></returns>
public static async Task<int> 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;
}
/// <summary>
/// 获取一个key的对象
/// </summary>