using System.Net; using System.Reflection; using System.Text.Json; using XFEExtension.NetCore.AutoConfig; using XFEExtension.NetCore.Exceptions; using XFEExtension.NetCore.ServerInteractive.Interfaces; using XFEExtension.NetCore.ServerInteractive.Models; using XFEExtension.NetCore.ServerInteractive.Models.ServerModels; using XFEExtension.NetCore.ServerInteractive.Models.UserModels; using XFEExtension.NetCore.ServerInteractive.Utilities.Helpers; using XFEExtension.NetCore.StringExtension; using XFEExtension.NetCore.XFETransform.Json; namespace XFEExtension.NetCore.ServerInteractive.Utilities.DataTable; /// /// XFE数据表格 /// /// public class XFEDataListTable : IXFEDataTable where T : IIdModel { private readonly SemaphoreSlim _operationGate = new(1, 1); /// public Func> GetEncryptedUserLoginModelFunction { get; set; } = () => []; /// public Func> GetUsersFunction { get; set; } = () => []; /// /// 获取列表的方法 /// public Func> GetTableFunction { get; set; } = () => []; /// /// 添加元素至列表的方法 /// public Action AddToTableFunction { get; set; } = _ => { }; /// /// 从列表中移除元素的方法 /// public Action RemoveFromTableFunction { get; set; } = _ => { }; /// /// 更改列表中元素的方法 /// public Action ChangeItemTableFunction { get; set; } = _ => { }; /// public string TableShowName { get; set; } = typeof(T).Name; /// public string TableName { get; set; } = typeof(T).Name; /// public string TableNameInRequest { get; set; } /// public int GetPermissionLevel { get; set; } /// public int RemovePermissionLevel { get; set; } /// public int ChangePermissionLevel { get; set; } /// public int AddPermissionLevel { get; set; } /// public JsonSerializerOptions? JsonSerializerOptions { get; set; } /// public JsonSerializerOptions? UserJsonSerializerOptions { get; set; } /// /// 创建列表并手动设置Get Set方法等 /// public XFEDataListTable() => TableNameInRequest = $"{TableName[0]}".ToLower() + TableName[1..]; /// /// 根据指定type自动设置Get Set方法 /// /// 继承于XFEProfile的配置文件类型 /// /// 对于自动设置Get Set方法的Table,请确保配置文件使用XFEProfile创建ProfileList,属性名称为XXXTable /// public XFEDataListTable(Type type) { TableNameInRequest = $"{TableName[0]}".ToLower() + TableName[1..]; var property = type.GetProperty($"{typeof(T).Name}Table", BindingFlags.Public | BindingFlags.Static); var profileListType = typeof(ProfileList); var addMethod = profileListType.GetMethod("Add", [typeof(T)]); var removeMethod = profileListType.GetMethod("Remove", [typeof(T)]); var saveMethod = type.GetMethod("SaveProfile", BindingFlags.Public | BindingFlags.Static); if (property is null || addMethod is null || removeMethod is null || saveMethod is null) return; GetTableFunction = () => property.GetValue(null) as ProfileList ?? []; AddToTableFunction = item => addMethod.Invoke(GetTableFunction(), [item]); RemoveFromTableFunction = id => { var table = GetTableFunction(); removeMethod.Invoke(table, [table.FirstOrDefault(item => item.Id == id)]); }; ChangeItemTableFunction = item => { var table = GetTableFunction(); var targetItem = table.FirstOrDefault(originItem => originItem.Id == item.Id); if (targetItem is null) return; foreach (var itemProperty in targetItem.GetType().GetProperties()) { itemProperty.SetValue(targetItem, itemProperty.GetValue(item)); } saveMethod.Invoke(null, []); }; } /// /// 获取列表 /// /// public IEnumerable GetList() => GetTableFunction(); /// /// 添加一个元素 /// /// public void Add(T item) => AddToTableFunction(item); /// /// 移除一个元素 /// /// public void Remove(string id) => RemoveFromTableFunction(id); /// /// 更改一个元素 /// /// public void Change(T item) => ChangeItemTableFunction(item); /// public async Task Execute(string execute, XFEJsonNode requestJsonNode, ServerCoreReturnArgs r) { var statusCode = HttpStatusCode.OK; await _operationGate.WaitAsync().ConfigureAwait(false); try { switch (execute) { case "get": Console.Write($"获取{TableShowName}列表请求"); UserHelper.ValidatePermission(requestJsonNode["session"]?.GetString(), requestJsonNode["deviceInfo"]?.GetString(), r.ClientIP, GetPermissionLevel, GetEncryptedUserLoginModelFunction(), GetUsersFunction(), r); List tableList = [.. GetTableFunction()]; var pageSize = requestJsonNode["pageSize"]?.GetValue() ?? requestJsonNode["pageCount"]?.GetValue() ?? -1; if (pageSize == -1) { await r.Args.ReplyAndClose(JsonSerializer.Serialize(new { totalCount = tableList.Count, lastPage = -1, dataList = tableList.Select(item => ExternalDataTableItem.From(item)).ToArray() }, GetResponseJsonOptions()), HttpStatusCode.OK, "application/json; charset=utf-8"); } else { var page = requestJsonNode["page"]?.GetValue() ?? 1; if (pageSize is < 1 or > 1000 || page < 1) throw r.Error("page 必须大于等于 1,pageSize 必须介于 1 和 1000 之间", HttpStatusCode.BadRequest); var skip = (long)(page - 1) * pageSize; await r.Args.ReplyAndClose(JsonSerializer.Serialize(new { totalCount = tableList.Count, lastPage = (int)Math.Ceiling((double)tableList.Count / pageSize), dataList = skip >= tableList.Count ? [] : tableList.Skip(checked((int)skip)).Take(pageSize).Select(item => ExternalDataTableItem.From(item)).ToArray() }, GetResponseJsonOptions()), HttpStatusCode.OK, "application/json; charset=utf-8"); } break; case "add": Console.Write($"添加{TableShowName}请求"); var item = JsonSerializer.Deserialize(Convert.FromBase64String(requestJsonNode["data"]?.GetString() ?? string.Empty), JsonSerializerOptions); if (item is null) { statusCode = HttpStatusCode.BadRequest; throw new StopAction(() => { }, $"\n无法使用Json转换目标{TableShowName}信息"); } Console.Write($":{item.Id}"); UserHelper.ValidatePermission(requestJsonNode["session"]?.GetString(), requestJsonNode["deviceInfo"]?.GetString(), r.ClientIP, AddPermissionLevel, GetEncryptedUserLoginModelFunction(), GetUsersFunction(), r); if (item is IUserInfo newUser && !UserHelper.PreparePasswordCredential(newUser)) throw r.Error("新用户必须提供密码", HttpStatusCode.BadRequest); if (item.Id.IsNullOrWhiteSpace()) item.Id = Guid.NewGuid().ToString("N"); if (IdModelHelper.HasSameId(item.Id, GetTableFunction().Cast())) throw r.Error($"{TableShowName}ID已存在:{item.Id}", HttpStatusCode.Conflict); item.Version = 1; Add(item); await r.Args.ReplyAndClose(JsonSerializer.Serialize(new { id = item.Id, version = item.Version }), HttpStatusCode.Created, "application/json; charset=utf-8"); break; case "remove": Console.Write($"删除{TableShowName}请求"); var id = requestJsonNode["id"]?.GetString(); Console.Write($":{id}"); UserHelper.ValidatePermission(requestJsonNode["session"]?.GetString(), requestJsonNode["deviceInfo"]?.GetString(), r.ClientIP, RemovePermissionLevel, GetEncryptedUserLoginModelFunction(), GetUsersFunction(), r); if (id.IsNullOrWhiteSpace()) { statusCode = HttpStatusCode.BadRequest; throw new StopAction(() => { }, $"{TableShowName}ID不能为空"); } if (!GetTableFunction().Any(existing => existing.Id == id)) throw r.Error($"未找到{TableShowName}:{id}", HttpStatusCode.NotFound); Remove(id); r.Args.Close(); break; case "change": Console.Write($"更改{TableShowName}请求"); item = JsonSerializer.Deserialize(Convert.FromBase64String(requestJsonNode["data"]?.GetString() ?? string.Empty), JsonSerializerOptions); if (item is null) { statusCode = HttpStatusCode.BadRequest; throw new StopAction(() => { }, $"\n无法使用Json转换目标{TableShowName}信息"); } Console.Write($":{item.Id}"); if (item.Id.IsNullOrWhiteSpace() || item.Id.IsNullOrWhiteSpace()) { statusCode = HttpStatusCode.BadRequest; throw new StopAction(() => { }, $"\n{TableShowName}ID不能为空"); } UserHelper.ValidatePermission(requestJsonNode["session"]?.GetString(), requestJsonNode["deviceInfo"]?.GetString(), r.ClientIP, ChangePermissionLevel, GetEncryptedUserLoginModelFunction(), GetUsersFunction(), r); var existingItem = GetTableFunction().FirstOrDefault(existing => existing.Id == item.Id); if (existingItem is null) throw r.Error($"未找到{TableShowName}:{item.Id}", HttpStatusCode.NotFound); if (item.Version != existingItem.Version) throw r.Error($"{TableShowName}已被其他请求修改,请刷新后重试", HttpStatusCode.Conflict); if (item is IUserInfo changedUser && existingItem is IUserInfo existingUser && !UserHelper.PreparePasswordCredential(changedUser, existingUser)) throw r.Error("用户密码凭据无效", HttpStatusCode.BadRequest); item.Version = checked(existingItem.Version + 1); Change(item); await r.Args.ReplyAndClose(JsonSerializer.Serialize(new { id = item.Id, version = item.Version }), HttpStatusCode.OK, "application/json; charset=utf-8"); break; default: Console.WriteLine($"[ERROR] 试图查询不存在的表格:{execute}"); await r.Args.ReplyAndClose($"试图查询不存在的表格:{execute}", HttpStatusCode.BadRequest); break; } } catch (ServerCoreReturnArgs returnArgs) { Console.WriteLine($"[WARN]({r.ServerCore.ServerCoreName}){returnArgs.ReturnMessage}"); await returnArgs.Args.ReplyAndClose(returnArgs.ReturnMessage, returnArgs.StatusCode); } catch (Exception ex) { Console.WriteLine($"[WARN]({r.ServerCore.ServerCoreName}){ExceptionHelper.GetExceptionMessage(ex)}"); Console.WriteLine($"[TRACE]{ex.StackTrace}"); await r.Args.ReplyAndClose("服务器内部异常", HttpStatusCode.InternalServerError); } finally { _operationGate.Release(); } return statusCode; } private JsonSerializerOptions? GetResponseJsonOptions() => typeof(IUserInfo).IsAssignableFrom(typeof(T)) ? UserJsonSerializerOptions ?? JsonSerializerOptions : JsonSerializerOptions; }