From ed5ea9ae4c2e1a9f114e2302a9b3ca20168535c8 Mon Sep 17 00:00:00 2001
From: sunpengfei <i@angelzzz.com>
Date: 星期二, 12 八月 2025 09:55:56 +0800
Subject: [PATCH] feat:开发

---
 FlexJobApi.Core/Utils/ResourceUtils/ResourceUtils.cs |  206 ++++++++++++++++++++++++++++++++-------------------
 1 files changed, 129 insertions(+), 77 deletions(-)

diff --git a/FlexJobApi.Core/Utils/ResourceUtils/ResourceUtils.cs b/FlexJobApi.Core/Utils/ResourceUtils/ResourceUtils.cs
index 5f02b3f..139d6ff 100644
--- a/FlexJobApi.Core/Utils/ResourceUtils/ResourceUtils.cs
+++ b/FlexJobApi.Core/Utils/ResourceUtils/ResourceUtils.cs
@@ -1,9 +1,11 @@
-锘縰sing FlexJobApi.User.Application;
+锘縰sing Consul;
 using Furion;
 using Furion.DatabaseAccessor;
+using Furion.DataEncryption;
 using Furion.DistributedIDGenerator;
 using Furion.DynamicApiController;
 using Furion.FriendlyException;
+using Furion.HttpRemote;
 using Mapster;
 using MediatR;
 using Microsoft.AspNetCore.Mvc;
@@ -11,16 +13,22 @@
 using Microsoft.AspNetCore.Mvc.Controllers;
 using Microsoft.AspNetCore.Routing;
 using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.Caching.Distributed;
 using Microsoft.Extensions.DependencyInjection;
 using System;
 using System.Collections.Generic;
 using System.ComponentModel;
+using System.Diagnostics;
 using System.Linq;
+using System.Net.Http;
+using System.Net.Http.Headers;
 using System.Reflection;
+using System.Resources;
 using System.Text;
 using System.Text.RegularExpressions;
 using System.Threading;
 using System.Threading.Tasks;
+using static System.Collections.Specialized.BitVector32;
 
 namespace FlexJobApi.Core
 {
@@ -37,15 +45,15 @@
             var traceId = App.GetTraceId() ?? IDGen.NextID().ToString();
             var scopeFactory = App.GetService<IServiceScopeFactory>();
             var serviceScope = scopeFactory.CreateScope();
-            var rep = serviceScope.ServiceProvider.GetRequiredService<IRepository<Resource>>();
             var provider = serviceScope.ServiceProvider.GetRequiredService<IDynamicApiRuntimeChangeProvider>();
+            var rep = serviceScope.ServiceProvider.GetRequiredService<IRepository<Resource>>();
             var xmlDoc = await XmlDocUtils.GetXmlDocAsync();
             var enumWebApiMethods = await EnumUtils.GetModel<EnumResourceMethod>();
             var resourceControllers = await EnumUtils.GetModel<EnumResourceController>();
-            var requests = App.Assemblies.SelectMany(it => it.GetTypes()).Where(it => typeof(IBaseRequest).IsAssignableFrom(it)).ToList();
-            var resources = await rep.AsQueryable()
-                .Where(it => !it.IsExpired)
-                .ToListAsync();
+            var requests = App.Assemblies
+                .SelectMany(it => it.GetTypes())
+                .Where(it => !it.IsAbstract && typeof(IBaseRequest).IsAssignableFrom(it))
+                .ToList();
             var models = new List<ResourceModel>();
             foreach (var request in requests)
             {
@@ -54,25 +62,21 @@
 
                 foreach (var controller in resourceAttribute.Controllers)
                 {
-                    var resourceController = controller.GetType().GetMember(controller.ToString())[0].GetCustomAttribute<ResourceControllerAttribute>();
-                    var resourceService = resourceController.Service.GetType().GetMember(resourceController.Service.ToString())[0].GetCustomAttribute<ResourceServiceAttribute>();
+                    var requestXmlDoc = await request.GetXmlDocMemberAsync(xmlDoc);
+                    var resourceController = controller.GetCustomAttribute<EnumResourceController, ResourceControllerAttribute>();
+                    var resourceService = resourceController.Service.GetCustomAttribute<EnumResourceService, ResourceServiceAttribute>();
 
                     var model = new ResourceModel();
                     model.TraceId = traceId;
                     model.ApplicationName = resourceService.ApplicationName;
-                    model.RouteArea = resourceService.RouteArea;
-                    var name = request.Name;
-                    name = Regex.Replace(name, @"(Command|Query)$", "", RegexOptions.None);
-                    model.ActionName = name;
-                    model.Route = $"/api/{resourceService.RouteArea ?? "main"}/{controller}/{name}";
-                    var requestXmlDoc = await request.GetXmlDocMemberAsync(xmlDoc);
-                    model.Code = requestXmlDoc.Name;
                     model.Controller = controller;
                     model.ControllerSummary = resourceControllers.GetDescription(controller);
-                    if (controller == EnumResourceController.Role)
-                    {
-                        Console.WriteLine();
-                    }
+                    model.ActionName = Regex.Replace(request.Name, @"(Command|Query)$", "", RegexOptions.None);
+                    model.ActionSummary = requestXmlDoc?.Summary;
+                    model.Service = resourceController.Service;
+                    model.ServiceName = resourceService.ServiceName;
+                    model.RouteArea = resourceService.RouteArea;
+                    model.Route = $"/api/{resourceService.RouteArea ?? "main"}/{controller}/{model.ActionName}";
                     model.Method =
                         request.BaseType?.IsGenericType == true && request.BaseType.GetGenericTypeDefinition() == typeof(PagedListQuery<,>)
                         ? EnumResourceMethod.Post
@@ -85,7 +89,8 @@
                         : new List<string> { "Delete", "Remove ", "Clear" }.Any(it => request.Name.StartsWith(it, StringComparison.OrdinalIgnoreCase))
                         ? EnumResourceMethod.Delete
                         : EnumResourceMethod.Post;
-                    model.Name = requestXmlDoc?.Summary;
+                    model.Code = requestXmlDoc?.Name;
+                    model.Name = $"{model.ControllerSummary}-{model.ActionSummary}";
                     model.AllowAnonymous = resourceAttribute.AllowAnonymous;
                     model.RequestTypeName = request.Name;
                     model.RequestTypeFullName = request.FullName;
@@ -96,47 +101,78 @@
                         model.ResponseTypeName = responseType.GetCSharpFriendlyName();
                         model.ResponseTypeFullName = responseType.FullName;
                     }
-
-                    var resource = resources.FirstOrDefault(it => it.Route == model.Route && it.Method == model.Method);
-                    if (resource == null)
-                    {
-                        resource = new Resource();
-                        model.Adapt(resource);
-                        await rep.InsertAsync(resource);
-                        resources.Add(resource);
-                    }
-                    else
-                    {
-                        model.Adapt(resource);
-                        await rep.UpdateAsync(resource);
-                    }
-
                     models.Add(model);
+
+                    await App.GetRequiredService<IDistributedCache>().SetStringAsync($"ResourceModel|{model.RequestTypeFullName}", model.ToJson());
                 }
             }
 
-            var expiredResources = resources.Where(it => it.TraceId != traceId).ToList();
-            foreach (var expiredResource in expiredResources)
+            var resources = await SaveResourcesAsync(models, rep);
+
+            DynamicControllersHotPlug(resources, provider);
+
+            await rep.SaveNowAsync();
+        }
+
+        /// <summary>
+        /// 淇濆瓨璧勬簮
+        /// </summary>
+        /// <param name="models"></param>
+        /// <param name="traceId"></param>
+        /// <param name="rep"></param>
+        /// <returns></returns>
+        private static async Task<List<Resource>> SaveResourcesAsync(List<ResourceModel> models, IRepository<Resource> rep = null)
+        {
+            rep = rep ?? Db.GetRepository<Resource>();
+            var resources = await rep.AsQueryable()
+                .Where(it => !it.IsExpired)
+                .ToListAsync();
+            foreach (var model in models)
             {
-                expiredResource.IsExpired = true;
-                await rep.UpdateAsync(expiredResource);
+                var resource = resources.FirstOrDefault(it => it.Route == model.Route && it.Method == model.Method);
+                if (resource == null)
+                {
+                    resource = new Resource();
+                    resource.Id = IDGen.NextID();
+                    resource.CreatedTime = DateTimeOffset.Now;
+                    model.Adapt(resource);
+                    await rep.InsertAsync(resource);
+                    resources.Add(resource);
+                }
+                else
+                {
+                    var resourceBakModel = new ResourceModel();
+                    resource.Adapt(resourceBakModel);
+                    resourceBakModel.TraceId = model.TraceId;
+                    resourceBakModel.DynamicAssemblyName = model.DynamicAssemblyName;
+                    if (resourceBakModel.ToJson() != model.ToJson())
+                    {
+                        model.Adapt(resource);
+                        resource.UpdatedTime = DateTimeOffset.Now;
+                        await rep.UpdateAsync(resource);
+                    }
+                }
             }
 
-            var controllers = models
-                .GroupBy(it => new
-                {
-                    it.Controller,
-                    it.ControllerSummary,
-                    it.ApplicationName,
-                    it.RouteArea
-                })
-                .Select(it => new
-                {
-                    it.Key,
-                    Actions = it.ToList()
-                })
-                .ToList();
-            foreach (var controller in controllers)
+            var expiredResources = resources.Where(it => !models.Any(m => m.Route == it.Route && m.Method == it.Method)).ToList();
+            foreach (var expiredResource in expiredResources)
+            {
+                resources.Remove(expiredResource);
+                await rep.DeleteAsync(expiredResource);
+            }
+
+            return resources.Where(it => !it.IsExpired).ToList();
+        }
+
+        /// <summary>
+        /// 鍔ㄦ�佹帶鍒跺櫒鐑彃
+        /// </summary>
+        /// <param name="resources"></param>
+        /// <param name="provider"></param>
+        public static void DynamicControllersHotPlug(List<Resource> resources, IDynamicApiRuntimeChangeProvider provider = null)
+        {
+            provider = provider ?? App.GetRequiredService<IDynamicApiRuntimeChangeProvider>();
+            foreach (var resource in resources)
             {
                 var code = $@"
 using FlexJobApi.Core;
@@ -150,46 +186,62 @@
 using System.Collections.Generic;
 using System.ComponentModel;
 
-namespace {controller.Key.ApplicationName}
+namespace {resource.ApplicationName}.{resource.Controller}.{resource.ActionName}Request
 {{
     /// <summary>
-    /// {controller.Key.ControllerSummary}
+    /// {resource.ControllerSummary}
     /// </summary>
-    [Route(""api/{controller.Key.RouteArea}/[controller]"")]
-    public class {controller.Key.Controller}AppService(IMediator mediator) : IDynamicApiController
+    [Route(""api/{resource.RouteArea}/[controller]"")]
+    public class {resource.Controller}AppService(IMediator mediator) : IDynamicApiController
     {{
-        private readonly IMediator mediator = mediator;";
-                foreach (var action in controller.Actions)
-                {
-                    code += $@"
+        private readonly IMediator mediator = mediator;
 
         /// <summary>
-        /// {action.Name}
+        /// {resource.ActionSummary}
         /// </summary>
         /// <param name=""request""></param>
         /// <returns></returns>";
-                    if (action.AllowAnonymous)
-                    {
-                        code += $@"
-        [AllowAnonymous]";
-                    }
+                if (resource.AllowAnonymous)
+                {
                     code += $@"
-        [Http{action.Method}]
-        public Task<{action.ResponseTypeName}> {action.ActionName}({action.RequestTypeName} request)
+        [AllowAnonymous]";
+                }
+                var result = resource.ResponseTypeName.IsNull() ? "Task" : $"Task<{resource.ResponseTypeName}>";
+                code += $@"
+        [Http{resource.Method}]
+        public {result} {resource.ActionName}({resource.RequestTypeName} request)
         {{
             return mediator.Send(request);
         }}
-";
-                }
-                code += $@"
+
     }}
 }}
 ";
-                var dynamicAssembly = App.CompileCSharpClassCode(code);
-                provider.AddAssembliesWithNotifyChanges(dynamicAssembly);
+                try
+                {
+                    var dynamicAssembly = App.CompileCSharpClassCode(code);
+                    provider.AddAssembliesWithNotifyChanges(dynamicAssembly);
+                    var dynamicAssemblyName = dynamicAssembly.GetName().Name;
+                    resource.DynamicAssemblyName = dynamicAssemblyName;
+                }
+                catch (Exception ex)
+                {
+                    Console.WriteLine(code);
+                    throw;
+                }
             }
 
-            await rep.SaveNowAsync();
+        }
+
+        /// <summary>
+        /// 鍔ㄦ�佹帶鍒跺櫒鐑嫈
+        /// </summary>
+        /// <param name="resource"></param>
+        /// <param name="provider"></param>
+        public static void DynamicControllerHotPluck(Resource resource, IDynamicApiRuntimeChangeProvider provider = null)
+        {
+            provider = provider ?? App.GetRequiredService<IDynamicApiRuntimeChangeProvider>();
+            provider.RemoveAssembliesWithNotifyChanges(resource.DynamicAssemblyName);
         }
 
         /// <summary>
@@ -197,7 +249,7 @@
         /// </summary>
         /// <param name="type"></param>
         /// <returns></returns>
-        public static string GetCSharpFriendlyName(this Type type)
+        private static string GetCSharpFriendlyName(this Type type)
         {
             // 澶勭悊鍙┖绫诲瀷
             if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))

--
Gitblit v1.9.1