CrazyIter_Bin 9 ヶ月 前
コミット
917f69ec1a

+ 3 - 3
TEAMModelBI/TEAMModelBI.csproj

@@ -65,9 +65,9 @@
 		<SpaRoot>ClientApp\</SpaRoot>
 		<DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
 		<UserSecretsId>078b5d89-7d90-4f6a-88fc-7d96025990a8</UserSecretsId>
-		<Version>5.2408.7</Version>
-		<AssemblyVersion>5.2408.7.1</AssemblyVersion>
-		<FileVersion>5.2408.7.1</FileVersion>
+		<Version>5.2408.14</Version>
+		<AssemblyVersion>5.2408.14.1</AssemblyVersion>
+		<FileVersion>5.2408.14.1</FileVersion>
 		<Description>TEAMModelBI(BI)</Description>
 		<PackageReleaseNotes>BI版本说明版本切换标记2022000908</PackageReleaseNotes>
 		<PackageId>TEAMModelBI</PackageId>

BIN
TEAMModelOS.Extension/HTEX.Complex/JsonFiles/ip2region.db


ファイルの差分が大きいため隠しています
+ 42708 - 0
TEAMModelOS.Extension/HTEX.Complex/JsonFiles/latlng.json


+ 12 - 21
TEAMModelOS.Extension/HTEX.Complex/Program.cs

@@ -6,6 +6,7 @@ using Microsoft.IdentityModel.Tokens;
 using System.IdentityModel.Tokens.Jwt;
 using TEAMModelOS.SDK.DI;
 using TEAMModelOS.SDK;
+using HTEX.Complex.Services;
 namespace HTEX.Complex
 {
     public class Program
@@ -56,30 +57,15 @@ namespace HTEX.Complex
             builder.Services.AddEndpointsApiExplorer();
             //builder.Services.AddSwaggerGen();
             builder.Services.AddHttpClient();
-            string StorageConnectionString = builder.Configuration.GetValue<string>("Azure:Storage:ConnectionString");
-            string StorageConnectionStringTest = builder.Configuration.GetValue<string>("Azure:Storage:ConnectionString-Test");
-
-            //string ServiceBusConnectionString = builder.Configuration.GetValue<string>("Azure:ServiceBus:ConnectionString");
-            //string ServiceBusConnectionStringTest = builder.Configuration.GetValue<string>("Azure:ServiceBus:ConnectionString-Test");
-
-            string RedisConnectionString = builder.Configuration.GetValue<string>("Azure:Redis:ConnectionString");
-            string RedisConnectionStringTest = builder.Configuration.GetValue<string>("Azure:Redis:ConnectionString-Test");
-
-            string CosmosConnectionString = builder.Configuration.GetValue<string>("Azure:Cosmos:ConnectionString");
-            string CosmosConnectionStringTest = builder.Configuration.GetValue<string>("Azure:Cosmos:ConnectionString-Test");
-
+            string? StorageConnectionString = builder.Configuration.GetValue<string>("Azure:Storage:ConnectionString");
+            string? RedisConnectionString = builder.Configuration.GetValue<string>("Azure:Redis:ConnectionString");
+            string? CosmosConnectionString = builder.Configuration.GetValue<string>("Azure:Cosmos:ConnectionString");
             //Storage
             builder.Services.AddAzureStorage(StorageConnectionString, "Default");
-            builder.Services.AddAzureStorage(StorageConnectionStringTest, "Test");
-            //ServiceBus
-            //builder.Services.AddAzureServiceBus(ServiceBusConnectionString, "Default");
-            //builder.Services.AddAzureServiceBus(ServiceBusConnectionStringTest, "Test");
             //Redis
             builder.Services.AddAzureRedis(RedisConnectionString, "Default");
-            builder.Services.AddAzureRedis(RedisConnectionStringTest, "Test");
             //Cosmos
             builder.Services.AddAzureCosmos(CosmosConnectionString, "Default");
-            builder.Services.AddAzureCosmos(CosmosConnectionStringTest, "Test");
 
             //MQTT  服务端API 发送消息到MQTT客户端 https://www.cnblogs.com/weskynet/p/16441219.html
             builder.Services.AddSignalR();
@@ -126,9 +112,14 @@ namespace HTEX.Complex
             app.UseHttpsRedirection(); //開發中暫時關掉
             app.UseAuthentication();
             app.UseAuthorization();
-            app.MapControllerRoute(
-                name: "default",
-                pattern: "{controller=Home}/{action=Index}/{id?}");
+            //app.MapControllerRoute(
+            //    name: "default",
+            //    pattern: "{controller=Home}/{action=Index}/{id?}");
+            app.UseEndpoints(endpoints => {
+                endpoints.MapControllers();
+                endpoints.MapFallbackToFile("index.html");
+                endpoints.MapHub<SignalRScreenServerHub>("/signalr/screen").RequireCors("any");
+            });
             app.Run();
         }
     }

+ 68 - 48
TEAMModelOS.Extension/HTEX.Complex/Services/SignalRScreenServerHub.cs

@@ -5,14 +5,20 @@ using Microsoft.Extensions.Primitives;
 using TEAMModelOS.SDK.DI;
 using TEAMModelOS.SDK.Extension;
 using TEAMModelOS.SDK;
+using System.Web;
+using System.Text;
+
+using StackExchange.Redis;
 namespace HTEX.Complex.Services
 {
     public class SignalRScreenServerHub : Hub<IClient>
     {
-        private readonly AzureRedisFactory _azureRedis;
 
-        public SignalRScreenServerHub(AzureRedisFactory azureRedis)
+        private readonly ILogger<SignalRScreenServerHub> _logger;
+        private readonly AzureRedisFactory _azureRedis;
+        public SignalRScreenServerHub(AzureRedisFactory azureRedis, ILogger<SignalRScreenServerHub> logger)
         {
+            _logger = logger;
             _azureRedis = azureRedis;
         }
 
@@ -21,7 +27,6 @@ namespace HTEX.Complex.Services
         /// </summary>
         /// <returns></returns>
         public override async Task OnConnectedAsync()
-
         {
             var connid = Context.ConnectionId;
             var httpContext = Context.GetHttpContext();
@@ -31,7 +36,8 @@ namespace HTEX.Complex.Services
                 //wss://www.winteach.cn/signalr/notify?grant_type=bookjs_api&clientid={clientid}&id=客户端自动生成的
                 httpContext.Request.Query.TryGetValue("grant_type", out StringValues grant_type);
                 httpContext.Request.Query.TryGetValue("clientid", out StringValues clientid);
-                var ip = GetIP(httpContext);
+                httpContext.Request.Query.TryGetValue("device", out StringValues _device);
+
                 await Groups.AddToGroupAsync(connid, grant_type!);
                 if (!clientid.Equals(StringValues.Empty) && !grant_type.Equals(StringValues.Empty)) {
 
@@ -43,55 +49,66 @@ namespace HTEX.Complex.Services
                         grant_type = grant_type,
                         clientid= clientid
                     };
-                    await _azureRedis.GetRedisClient(8).StringSetAsync($"SignalRClient:connects:{connid}", client.ToJsonString());
+                    await _azureRedis.GetRedisClient(8).HashSetAsync($"SignalRClient:connects", connid, client.ToJsonString());
+                    ClientDevice device = HttpUtility.UrlDecode(_device, Encoding.Unicode).ToObject<ClientDevice>();
                     switch (true) 
                     {
                         case bool when grant_type.Equals(ScreenConstant.grant_type):
-                            ScreenClient screenClient = null;
+                            ScreenClient screenClient ;
                             var value = await _azureRedis.GetRedisClient(8).HashGetAsync($"ScreenApi:clients", client.clientid);
                             if (value!=default  && value.HasValue)
                             {
                                 screenClient = value.ToString().ToObject<ScreenClient>();
-                                // 这里不强制设置free ,因为如果是重连,可能正在执行命令,需要等待执行完成
+                                
+                                // 这里不强制设置free ,因为如果是重连,可能正在执行任务,需要等待执行完成
                                 //screenClient.status="free";
-                                screenClient.connid=connid;
+
+                                //先检查状态是否是在忙碌,在时间戳范围里,如果不在时间戳范围,强制free。
+                                if (!screenClient.status!.Equals(ScreenConstant.free) && screenClient.last_time  + screenClient.timeout+ screenClient.delay + ScreenConstant.time_excess < DateTimeOffset.UtcNow.ToUnixTimeMilliseconds())
+                                {
+                                    screenClient.status = ScreenConstant.free;
+                                }
                             }
                             else 
                             {
-                                screenClient= new ScreenClient
+                                screenClient = new ScreenClient
                                 {
-                                    status=ScreenConstant.free,
-                                    connid=connid,
-                                    grant_type=grant_type,
-                                    clientid= clientid,
-                                    desc="",
-                                    domain="",
-                                    ip=ip,
-                                    time= DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
-                                    weight= 0,
-                                    duration=0,
+                                    status = ScreenConstant.free,
                                 };
                             }
+                            screenClient.connid=connid;
+                            screenClient.grant_type = grant_type;
+                            screenClient.clientid = clientid;
+                            screenClient.os = device.os;
+                            screenClient.port = device.port;
+                            screenClient.name = device.name;
+                            screenClient.region = device.region;
+                            screenClient.remote = device.remote;
+                            screenClient.networks = device.networks;
+                            screenClient.screenUrl = device.screenUrl;
+                            screenClient.delay = device.delay;
+                            screenClient.timeout = device.timeout;
+                            screenClient.last_time= DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
                             //连接成功,发送消息给客户端。
                             await SendConnection(connid, new ConnectionMessageContent
                             {
+                                connid=connid,
                                 clientid = clientid,
-                                status = ScreenConstant.free,
+                                status = screenClient.status,
                                 grant_type = grant_type,
+                                message_type= MessageType.conn_success,
                                 content = $"连接成功"
                             });
-                            //先检查状态是否是在忙碌,在时间戳范围里,如果不在时间戳范围,强制free。
-                            if (!screenClient.status!.Equals(ScreenConstant.free) &&screenClient.time  + screenClient.duration < DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()) {
-                                screenClient.status = ScreenConstant.free;
-                            }
+                            _logger.LogInformation($"客户端连接成功=>{screenClient.name},{clientid}:\n{screenClient.ToJsonString()}");
                             if (screenClient.status!.Equals(ScreenConstant.free)) {
+                                _logger.LogInformation($"客户端当前空闲=>{screenClient.name},{clientid},分发任务......");
                                 //连接成功,马上分发任务。
                                 //从尾部弹出元素,队列先进先出
                                 var queueValue = await _azureRedis.GetRedisClient(8).ListRightPopAsync("PDFGen:Queue");
                                 if (queueValue!=default && queueValue.HasValue)
                                 {
                                     PDFGenQueue genQueue = queueValue.ToString().ToObject<PDFGenQueue>();
-                                    await SendConnection(connid, new ScreenProcessMessageContent
+                                    await SendMessage(connid, new ScreenProcessMessageContent
                                     {
                                         clientid = clientid,
                                         status = ScreenConstant.busy,
@@ -99,9 +116,11 @@ namespace HTEX.Complex.Services
                                         content =$"{queueValue.ToString()}",//从Redis中获取任务信息
                                     });
                                     screenClient.status =  ScreenConstant.busy;
-                                    screenClient.time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
-                                    //预计占用时长,并冗余5秒
-                                    screenClient.duration= genQueue.timeout+genQueue.delay+ScreenConstant.time_excess;
+                                    screenClient.last_time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
+                                }
+                                else {
+                                    _logger.LogInformation($"客户端当前空闲=>{screenClient.name},{clientid},暂无任务可领取的任务......");
+                                  
                                 }
                             }
                             await _azureRedis.GetRedisClient(8).HashSetAsync($"ScreenApi:clients", client.clientid, screenClient.ToJsonString());
@@ -115,6 +134,7 @@ namespace HTEX.Complex.Services
                         clientid = string.Empty,
                         status =ScreenConstant.error,
                         grant_type = grant_type,
+                        message_type= MessageType.conn_error,
                         content = "客户端配置错误",
                         connid = connid,
                     });
@@ -125,44 +145,44 @@ namespace HTEX.Complex.Services
         public async override Task OnDisconnectedAsync(Exception? exception)
         {
             var connid = Context.ConnectionId;
-            var redisData = await _azureRedis.GetRedisClient(8).StringGetAsync($"SignalRClient:connects:{connid}");
+            var redisData = await _azureRedis.GetRedisClient(8).HashGetAsync($"SignalRClient:connects", connid);
+            _logger.LogInformation($"客户端断开连接=>{connid} ");
+            ///连接配置,并且使用钉钉 离线通知。
             if (!redisData.IsNullOrEmpty)
             {
-                await _azureRedis.GetRedisClient(8).KeyDeleteAsync($"SignalRClient:connects:{connid}");
                 var client = redisData.ToString().ToObject<SignalRClient>();
+                await _azureRedis.GetRedisClient(8).HashDeleteAsync($"SignalRClient:connects", connid);
                 if (client != null)
                 {
+                    await Groups.RemoveFromGroupAsync(connid, client.grant_type!);
                     var value =  await _azureRedis.GetRedisClient(8).HashGetAsync($"ScreenApi:clients", client.clientid);
                     if (value!=default  && value.HasValue) 
                     {
                         ScreenClient screenClient = value.ToString().ToObject<ScreenClient>() ;
-                        screenClient.status=ScreenConstant.down;
-                        screenClient.connid= string.Empty;
-                        await _azureRedis.GetRedisClient(8).HashSetAsync($"ScreenApi:clients", client.clientid, screenClient.ToJsonString());
+                        _logger.LogInformation($"客户端断开连接=>{connid},{screenClient.name},{screenClient.clientid} ");
+                        long now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
+                        // 判断是否过期
+                        if (screenClient.status!.Equals(ScreenConstant.busy )  &&    screenClient.last_time+screenClient.timeout+screenClient.delay+ ScreenConstant.time_excess <=now)
+                        {
+                            screenClient.status=ScreenConstant.down;
+                            screenClient.connid= string.Empty;
+                            await _azureRedis.GetRedisClient(8).HashSetAsync($"ScreenApi:clients", client.clientid, screenClient.ToJsonString());
+                        }
                     }
-                    await Groups.RemoveFromGroupAsync(connid, client.grant_type!);
-                    ///连接配置,并且使用钉钉 离线通知。
                 }
             }
         }
-
         public async Task SendConnection(string connectionId, MessageBody msg)
         {
             await Clients.Client(connectionId).ReceiveConnection(msg);
         }
-        public string GetIP(HttpContext httpContext)
+        public async Task SendMessage(string connectionId,  MessageBody msg)
         {
-            var IpPort = httpContext.Request.Headers["X-Forwarded-For"].FirstOrDefault();
-            if (string.IsNullOrEmpty(IpPort))
-            {
-                IpPort = $"{httpContext.Connection.RemoteIpAddress}";
-            }
-            if (IpPort.Contains("::"))
-            {
-                IpPort = "127.0.0.1";
-            }
-            return IpPort;
+            await Clients.Client(connectionId).ReceiveMessage(msg);
+        }
+        public async Task SendDisConnection(string connectionId, MessageBody msg)
+        {
+            await Clients.Client(connectionId).ReceiveDisConnection(msg);
         }
     }
-
 }

+ 4 - 8
TEAMModelOS.Extension/HTEX.Complex/appsettings.Development.json

@@ -8,20 +8,16 @@
   "AllowedHosts": "*",
   "Azure": {
     "Storage": {
-      "ConnectionString": "DefaultEndpointsProtocol=https;AccountName=teammodelos;AccountKey=Dl04mfZ9hE9cdPVO1UtqTUQYN/kz/dD/p1nGvSq4tUu/4WhiKcNRVdY9tbe8620nPXo/RaXxs+1F9sVrWRo0bg==;EndpointSuffix=core.chinacloudapi.cn",
-      "ConnectionString-Test": "DefaultEndpointsProtocol=https;AccountName=teammodeltest;AccountKey=O2W2vadCqexDxWO+px+QK7y1sHwsYj8f/WwKLdOdG5RwHgW/Dupz9dDUb4c1gi6ojzQaRpFUeAAmOu4N9E+37A==;EndpointSuffix=core.chinacloudapi.cn"
+      "ConnectionString": "DefaultEndpointsProtocol=https;AccountName=teammodeltest;AccountKey=O2W2vadCqexDxWO+px+QK7y1sHwsYj8f/WwKLdOdG5RwHgW/Dupz9dDUb4c1gi6ojzQaRpFUeAAmOu4N9E+37A==;EndpointSuffix=core.chinacloudapi.cn"
     },
     "ServiceBus": {
-      "ConnectionString": "Endpoint=sb://coreservicebuscn.servicebus.chinacloudapi.cn/;SharedAccessKeyName=TEAMModelOS;SharedAccessKey=xO8HcvXXuuEkuFI0KlV5uXs8o6vyuVqTR+ASbPGMhHo=",
-      "ConnectionString-Test": "Endpoint=sb://coreservicebuscn.servicebus.chinacloudapi.cn/;SharedAccessKeyName=TEAMModelOS;SharedAccessKey=xO8HcvXXuuEkuFI0KlV5uXs8o6vyuVqTR+ASbPGMhHo="
+      "ConnectionString": "Endpoint=sb://coreservicebuscn.servicebus.chinacloudapi.cn/;SharedAccessKeyName=TEAMModelOS;SharedAccessKey=xO8HcvXXuuEkuFI0KlV5uXs8o6vyuVqTR+ASbPGMhHo="
     },
     "Redis": {
-      "ConnectionString": "CoreRedisCN.redis.cache.chinacloudapi.cn:6380,password=LyJWP1ORJdv+poXWofAF97lhCEQPg1wXWqvtzXGXQuE=,ssl=True,abortConnect=False",
-      "ConnectionString-Test": "52.130.252.100:6379,password=habook,ssl=false,abortConnect=False,writeBuffer=10240"
+      "ConnectionString": "52.130.252.100:6379,password=habook,ssl=false,abortConnect=False,writeBuffer=10240"
     },
     "Cosmos": {
-      "ConnectionString": "AccountEndpoint=https://cdhabookdep-free.documents.azure.cn:443/;AccountKey=JTUVk92Gjsx17L0xqxn0X4wX2thDPMKiw4daeTyV1HzPb6JmBeHdtFY1MF1jdctW1ofgzqkDMFOtcqS46by31A==;",
-      "ConnectionString-Test": "AccountEndpoint=https://cdhabookdep-free.documents.azure.cn:443/;AccountKey=JTUVk92Gjsx17L0xqxn0X4wX2thDPMKiw4daeTyV1HzPb6JmBeHdtFY1MF1jdctW1ofgzqkDMFOtcqS46by31A==;"
+      "ConnectionString": "AccountEndpoint=https://cdhabookdep-free.documents.azure.cn:443/;AccountKey=JTUVk92Gjsx17L0xqxn0X4wX2thDPMKiw4daeTyV1HzPb6JmBeHdtFY1MF1jdctW1ofgzqkDMFOtcqS46by31A==;"
     }
   }
 }

+ 0 - 4
TEAMModelOS.Extension/HTEX.Complex/appsettings.json

@@ -9,19 +9,15 @@
   "Azure": {
     "Storage": {
       "ConnectionString": "DefaultEndpointsProtocol=https;AccountName=teammodelos;AccountKey=Dl04mfZ9hE9cdPVO1UtqTUQYN/kz/dD/p1nGvSq4tUu/4WhiKcNRVdY9tbe8620nPXo/RaXxs+1F9sVrWRo0bg==;EndpointSuffix=core.chinacloudapi.cn",
-      "ConnectionString-Test": "DefaultEndpointsProtocol=https;AccountName=teammodeltest;AccountKey=O2W2vadCqexDxWO+px+QK7y1sHwsYj8f/WwKLdOdG5RwHgW/Dupz9dDUb4c1gi6ojzQaRpFUeAAmOu4N9E+37A==;EndpointSuffix=core.chinacloudapi.cn"
     },
     "ServiceBus": {
       "ConnectionString": "Endpoint=sb://coreservicebuscn.servicebus.chinacloudapi.cn/;SharedAccessKeyName=TEAMModelOS;SharedAccessKey=xO8HcvXXuuEkuFI0KlV5uXs8o6vyuVqTR+ASbPGMhHo=",
-      "ConnectionString-Test": "Endpoint=sb://coreservicebuscn.servicebus.chinacloudapi.cn/;SharedAccessKeyName=TEAMModelOS;SharedAccessKey=xO8HcvXXuuEkuFI0KlV5uXs8o6vyuVqTR+ASbPGMhHo="
     },
     "Redis": {
       "ConnectionString": "CoreRedisCN.redis.cache.chinacloudapi.cn:6380,password=LyJWP1ORJdv+poXWofAF97lhCEQPg1wXWqvtzXGXQuE=,ssl=True,abortConnect=False",
-      "ConnectionString-Test": "52.130.252.100:6379,password=habook,ssl=false,abortConnect=False,writeBuffer=10240"
     },
     "Cosmos": {
       "ConnectionString": "AccountEndpoint=https://teammodelos.documents.azure.cn:443/;AccountKey=clF73GwPECfP1lKZTCvs8gLMMyCZig1HODFbhDUsarsAURO7TcOjVz6ZFfPqr1HzYrfjCXpMuVD5TlEG5bFGGg==;",
-      "ConnectionString-Test": "AccountEndpoint=https://cdhabookdep-free.documents.azure.cn:443/;AccountKey=JTUVk92Gjsx17L0xqxn0X4wX2thDPMKiw4daeTyV1HzPb6JmBeHdtFY1MF1jdctW1ofgzqkDMFOtcqS46by31A==;"
     }
   }
 }

BIN
TEAMModelOS.Extension/HTEX.ScreenClient.zip


+ 13 - 0
TEAMModelOS.Extension/HTEX.ScreenClient/.config/dotnet-tools.json

@@ -0,0 +1,13 @@
+{
+  "version": 1,
+  "isRoot": true,
+  "tools": {
+    "dotnet-ef": {
+      "version": "8.0.7",
+      "commands": [
+        "dotnet-ef"
+      ],
+      "rollForward": false
+    }
+  }
+}

+ 2 - 0
TEAMModelOS.Extension/HTEX.ScreenClient/Controllers/WeatherForecastController.cs

@@ -1,3 +1,4 @@
+using Microsoft.AspNetCore.Hosting.Server.Features;
 using Microsoft.AspNetCore.Mvc;
 
 namespace HTEX.ScreenClient.Controllers
@@ -21,6 +22,7 @@ namespace HTEX.ScreenClient.Controllers
         [HttpGet]
         public IEnumerable<WeatherForecast> Get()
         {
+            
             return Enumerable.Range(1, 5).Select(index => new WeatherForecast
             {
                 Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),

+ 8 - 0
TEAMModelOS.Extension/HTEX.ScreenClient/HTEX.ScreenClient.csproj

@@ -6,4 +6,12 @@
     <ImplicitUsings>enable</ImplicitUsings>
   </PropertyGroup>
 
+  <ItemGroup>
+    <PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="8.0.7" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\..\TEAMModelOS.SDK\TEAMModelOS.SDK.csproj" />
+  </ItemGroup>
+
 </Project>

+ 22 - 6
TEAMModelOS.Extension/HTEX.ScreenClient/Program.cs

@@ -1,26 +1,42 @@
+using HTEX.ScreenClient.Services;
+using Microsoft.AspNetCore.Hosting.Server;
+using Microsoft.AspNetCore.Hosting.Server.Features;
+using Microsoft.Extensions.Hosting;
+using System.Net;
+using System.Net.NetworkInformation;
+using System.Runtime.InteropServices;
+
 namespace HTEX.ScreenClient
 {
     public class Program
     {
         public static void Main(string[] args)
         {
+      
             var builder = WebApplication.CreateBuilder(args);
+   
+            builder.Services.AddControllers();
+            builder.Services.AddHttpClient();
+            builder.Services.AddHttpContextAccessor();
 
-            // Add services to the container.
 
-            builder.Services.AddControllers();
+            builder.WebHost.UseKestrel(options => {
+                //options.ListenAnyIP(4001, options => {
+                //   // options.UseHttps("Crt/iteden.pfx", "iteden"); 
+                //});
+                options.ListenAnyIP(1883, options => {/*options.UseHttps("Crt/iteden.pfx", "iteden");*/ });
+                options.ListenAnyIP(5000, options => {/* options.UseHttps("Configs/Crt/iteden.pfx", "iteden"); */}); // Default HTTP pipeline
+            });
 
-            var app = builder.Build();
 
+            builder.Services.AddHostedService<SignalRClientHub>();
+            var app = builder.Build();
             // Configure the HTTP request pipeline.
 
             app.UseHttpsRedirection();
 
             app.UseAuthorization();
-
-
             app.MapControllers();
-
             app.Run();
         }
     }

+ 134 - 0
TEAMModelOS.Extension/HTEX.ScreenClient/Services/SignalRClientHub.cs

@@ -0,0 +1,134 @@
+
+using Microsoft.AspNetCore.Hosting.Server;
+using Microsoft.AspNetCore.Hosting.Server.Features;
+using Microsoft.AspNetCore.SignalR.Client;
+using Microsoft.Extensions.Configuration;
+using System.Net;
+using System.Net.NetworkInformation;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Text.Json;
+using System.Text.Json.Nodes;
+using System.Web;
+using TEAMModelOS.SDK;
+using TEAMModelOS.SDK.Extension;
+
+namespace HTEX.ScreenClient.Services
+{
+    public class SignalRClientHub : BackgroundService, IDisposable
+    {
+        private readonly IConfiguration _configuration; 
+        private readonly ILogger<SignalRClientHub> _logger;
+        private readonly IHttpClientFactory _httpClientFactory;
+        private readonly IServiceProvider _services;
+        private IEnumerable<string>? _url = new List<string>();
+        public SignalRClientHub(IConfiguration configuration,ILogger<SignalRClientHub> logger,IHttpClientFactory httpClientFactory, IServiceProvider services,IHostApplicationLifetime lifetime) 
+        {
+                
+            _configuration=configuration;
+            _logger=logger;
+            _httpClientFactory=httpClientFactory;
+            _services=services;
+            lifetime.ApplicationStarted.Register(() => {
+                var server = _services.GetService<IServer>();
+                _url = server?.Features.Get<IServerAddressesFeature>()?.Addresses;
+            });
+        }
+        private List<string> messages = new List<string>();
+        protected async override Task ExecuteAsync(CancellationToken stoppingToken)
+        {
+            var device =  await GetClientInfo();
+            string hashData = $"{device.name}-{device.remote}-{device.port}-{device.os}-{string.Join(",",device.networks.Select(x=>$"{x.mac}-{x.ip}"))}";
+            string clientid =  ShaHashHelper.GetSHA256(hashData);
+            string? CenterUrl = _configuration.GetSection("ScreenClient:CenterUrl").Value;
+            string? ScreenUrl = _configuration.GetSection("ScreenClient:ScreenUrl").Value;
+            long Timeout = _configuration.GetValue<long>("ScreenClient:Timeout");
+            long Delay = _configuration.GetValue<long>("ScreenClient:Delay");
+            device.timeout = Timeout;
+            device.delay = Delay;
+            device.screenUrl = ScreenUrl;
+            HubConnection hubConnection = new HubConnectionBuilder()
+               .WithUrl($"{CenterUrl}/signalr/screen?grant_type=bookjs_api&clientid={clientid}&device={HttpUtility.UrlEncode(device.ToJsonString(),Encoding.Unicode)}") //only one slash
+               .WithAutomaticReconnect()
+               .ConfigureLogging(logging =>
+               {
+                   logging.SetMinimumLevel(LogLevel.Information);
+                   logging.AddConsole();
+               })
+               .Build();
+            hubConnection.On<JsonElement>("ReceiveConnection", ( message) =>
+            {
+                var encodedMsg = $" {message}";
+                _logger.LogInformation($"连接成功:{message.ToJsonString()}");
+                messages.Add(encodedMsg);
+            });
+            hubConnection.On<JsonElement>("ReceiveMessage", (message) =>
+            {
+                var encodedMsg = $"{message}";
+                messages.Add(encodedMsg);
+            });
+            
+            await hubConnection.StartAsync();
+        }
+         
+        public async Task<ClientDevice> GetClientInfo()
+        {
+            string hostName =$"{Environment.UserName}-{Dns.GetHostName()}" ;
+            string os = RuntimeInformation.OSDescription;
+            //获取当前客户端的服务端口
+            var _httpClient = _httpClientFactory.CreateClient();
+            ClientDevice device = new ClientDevice { name =hostName, os= os };
+            HttpResponseMessage message = await _httpClient.PostAsJsonAsync("https://www.teammodel.cn/core/system-info", new { });
+            if (message.IsSuccessStatusCode)
+            {
+                JsonNode? json = JsonSerializer.Deserialize<JsonNode>(await message.Content.ReadAsStringAsync());
+                var ip =  json?["ip"];
+                var region = json?["region"];
+                _logger.LogInformation($"远程地址:{ip}");
+                _logger.LogInformation($"所属地区:{region}");
+                device.remote=ip?.ToString();
+                device.region=region?.ToString();
+            }
+            _logger.LogInformation($"计算机名:{hostName}");
+            _logger.LogInformation($"系统名称:{RuntimeInformation.OSDescription}");
+           
+            var nics = NetworkInterface.GetAllNetworkInterfaces();
+            foreach (var nic in nics)
+            {
+                if (nic.OperationalStatus == OperationalStatus.Up)
+                {
+                    var mac = nic.GetPhysicalAddress().ToString();
+                    var properties = nic.GetIPProperties();
+                    var unicastAddresses = properties.UnicastAddresses;
+                    foreach (var unicast in unicastAddresses)
+                    {
+                        if (unicast.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
+                        {
+                            var ip = unicast.Address.ToString();
+                            Network network= new Network() { mac=mac, ip=ip };
+                            if (!string.IsNullOrWhiteSpace(mac.ToString()))
+                            {
+                                device.networks.Add(network);
+                                _logger.LogInformation($"网卡地址: {mac}");
+                                _logger.LogInformation($"内网地址: {ip}");
+                            }
+                        }
+                    }
+                }
+            }
+            if (_url!=null) 
+            {
+                List<int> ports = new List<int>();
+                foreach (var url in _url)
+                {
+                    Uri uri = new Uri(url);
+                    ports.Add(uri.Port);
+                }
+                device.port= string.Join(",", ports);
+                _logger.LogInformation($"占用端口: {device.port}");
+            }
+            return device ;
+        }
+       
+    }
+}

+ 7 - 0
TEAMModelOS.Extension/HTEX.ScreenClient/appsettings.Development.json

@@ -4,5 +4,12 @@
       "Default": "Information",
       "Microsoft.AspNetCore": "Warning"
     }
+  },
+  "AllowedHosts": "*",
+  "ScreenClient": {
+    "ScreenUrl": "http://52.130.252.100:13000",
+    "Timeout": 30000,
+    "Delay": 500,
+    "CenterUrl": "https://localhost:7298"
   }
 }

+ 3 - 3
TEAMModelOS.Function/TEAMModelOS.Function.csproj

@@ -5,9 +5,9 @@
     <OutputType>Exe</OutputType>
     <ImplicitUsings>enable</ImplicitUsings>
     <Nullable>enable</Nullable>
-	<Version>5.2408.7</Version>
-	<AssemblyVersion>5.2408.7.1</AssemblyVersion>
-	<FileVersion>5.2408.7.1</FileVersion>
+	<Version>5.2408.14</Version>
+	<AssemblyVersion>5.2408.14.1</AssemblyVersion>
+	<FileVersion>5.2408.14.1</FileVersion>
 	<PackageId>TEAMModelOS.FunctionV4</PackageId>
 	<Authors>teammodel</Authors>
 	<Company>醍摩豆(成都)信息技术有限公司</Company>

+ 68 - 45
TEAMModelOS.SDK/Models/Service/GenPDFService.cs

@@ -608,7 +608,7 @@ namespace TEAMModelOS.SDK
 
 
 
-    public class ScreenClient
+    public class ScreenClient  : ClientDevice
     {
         /// <summary>
         /// 授权类型,bookjs_api 
@@ -623,33 +623,13 @@ namespace TEAMModelOS.SDK
         /// </summary>
         public string? connid { get; set; }
         /// <summary>
-        /// 描述
-        /// </summary>
-        public string? desc { get; set; }
-        /// <summary>
-        /// 服务域
-        /// </summary>
-        public string? domain { get; set; }
-        /// <summary>
         /// 状态  busy 忙碌,free 空闲,down 离线,error 错误
         /// </summary>
         public string? status { get; set; }
-
-        /// <summary>
-        /// 权重
-        /// </summary>
-        public int weight { get; set; }
         /// <summary>
         /// 最后更新时间
         /// </summary>
-        public long time { get; set; }
-        /// <summary>
-        /// 预计占用时长
-        /// </summary>
-        public long duration { get; set; }
-
-
-        public string ip { get; set; }
+        public long last_time { get; set; }
     }
 
     public class SignalRClient
@@ -679,7 +659,6 @@ namespace TEAMModelOS.SDK
         {
             time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
         }
-
         /// <summary>
         /// 连接id
         /// </summary>
@@ -688,33 +667,14 @@ namespace TEAMModelOS.SDK
         /// 客户端id
         /// </summary>
         public virtual string? clientid { get; set; }
-
-        /// <summary>
-        /// 描述
-        /// </summary>
-        public virtual string? desc { get; set; }
-        /// <summary>
-        /// 服务域
-        /// </summary>
-        public virtual string? domain { get; set; }
         /// <summary>
         /// 状态  busy 忙碌,free 空闲,down 离线,error 错误
         /// </summary>
         public virtual string? status { get; set; }
-        /// <summary>
-        /// 权重
-        /// </summary>
-        public virtual int weight { get; set; }
-
         /// <summary>
         /// 消息内容
         /// </summary>
         public virtual string? content { get; set; }
-
-        /// <summary>
-        /// 消息服务器标识  与服务端保持的状态 1 连线中
-        /// </summary>
-        //public virtual int connect { get; set; }
         /// <summary>
         /// 消息创建时间
         /// </summary>
@@ -723,15 +683,28 @@ namespace TEAMModelOS.SDK
         /// 授权类型,bookjs_api 
         /// </summary>
         public virtual string? grant_type { get; set; }
+        /// <summary>
+        /// 消息类型
+        /// </summary>
+        public virtual MessageType message_type { get; set; }
     }
+    /// <summary>
+    /// 连接消息
+    /// </summary>
     public class ConnectionMessageContent : MessageBody
     {
 
     }
+    /// <summary>
+    /// 断开连接消息
+    /// </summary>
     public class DisConnectionMessageContent : MessageBody
     {
 
     }
+    /// <summary>
+    /// 业务处理消息
+    /// </summary>
     public class ScreenProcessMessageContent : MessageBody
     {
     }
@@ -743,9 +716,59 @@ namespace TEAMModelOS.SDK
         public static readonly string free = "free";
         public static readonly string error = "error";
         public static readonly string down = "down";
-        public static readonly long time_excess = 5000;
         public static readonly string grant_type = "bookjs_api";
-
-
+        /// <summary>
+        /// 冗余时间
+        /// </summary>
+        public static readonly long time_excess = 5000;
+    }
+    public enum MessageType {
+        conn_success,
+        conn_error,
+        biz_task,
+    }
+    public class ClientDevice
+    {
+        /// <summary>
+        /// 机器名
+        /// </summary>
+        public string? name { get; set; }
+        /// <summary>
+        /// 操作系统
+        /// </summary>
+        public string? os { get; set; }
+        /// <summary>
+        /// 远程ip
+        /// </summary>
+        public string? remote { get; set; }
+        /// <summary>
+        /// 端口,可能有多个端口
+        /// </summary>
+        public string? port { get; set; }
+        /// <summary>
+        /// 地区
+        /// </summary>
+        public string? region { get; set; }
+        /// <summary>
+        /// 网卡 IP信息
+        /// </summary>
+        public List<Network> networks { get; set; } = new List<Network>();
+        /// <summary>
+        /// 超时时间,单位毫秒
+        /// </summary>
+        public long timeout { get; set; } = 30000;
+        /// <summary>
+        /// 延迟时间,单位毫秒
+        /// </summary>
+        public long delay { get; set; } = 3000;
+        /// <summary>
+        /// PDF服务地址
+        /// </summary>
+        public string? screenUrl { get; set; } 
+    }
+    public class Network
+    {
+        public string? mac { get; set; }
+        public string? ip { get; set; }
     }
 }

+ 3 - 3
TEAMModelOS.SDK/TEAMModelOS.SDK.csproj

@@ -1,9 +1,9 @@
 <Project Sdk="Microsoft.NET.Sdk">
 	<PropertyGroup>
 		<TargetFramework>net8.0</TargetFramework>
-		<Version>5.2408.7</Version>
-		<AssemblyVersion>5.2408.7.1</AssemblyVersion>
-		<FileVersion>5.2408.7.1</FileVersion>
+		<Version>5.2408.14</Version>
+		<AssemblyVersion>5.2408.14.1</AssemblyVersion>
+		<FileVersion>5.2408.14.1</FileVersion>
 		<PackageReleaseNotes>发版</PackageReleaseNotes>
 	</PropertyGroup>
 

+ 8 - 12
TEAMModelOS.TEST/Program.cs

@@ -11,20 +11,16 @@ namespace TEAMModelOS.TEST
     {
         static void Main(string[] args)
         {
-            var  url=  HttpUtility.UrlDecode("https://teammodelos.blob.core.chinacloudapi.cn/0-public/visitCnt/2345/202406125/55/05.json ");
-           var uri = new Uri(url);
+            string[] urls = { "http://localhost:5000", "https://127.0.0.1:5001", "http://localhost","https://localhost" };
+            foreach (var url in urls)
+            {
+                Uri uri = new Uri(url);
+                Console.WriteLine($"URL: {url}");
+                Console.WriteLine($"Port: {uri.Port}");
+            }
 
-            // 获取容器名,它是路径的第一个部分
-            string containerName = uri.Segments[1].TrimEnd('/');
 
-            // 获取文件的完整同级目录,这是文件路径中除了文件名和扩展名之外的部分
-            // 由于文件名是路径的最后一个部分,我们可以通过连接除了最后一个部分之外的所有部分来获取目录路径
-            string directoryPath = string.Join("", uri.Segments, 2, uri.Segments.Length - 3);
-
-            Console.WriteLine("Container Name: " + containerName);
-            Console.WriteLine("Directory Path: " + directoryPath);
-            string? fileName = Path.GetFileNameWithoutExtension(uri.AbsolutePath);
-            string b = Path.Combine(directoryPath!, $"{fileName}.pdf");
+           
         }
     }
 }

+ 1 - 0
TEAMModelOS/Startup.cs

@@ -57,6 +57,7 @@ namespace TEAMModelOS
         // This method gets called by the runtime. Use this method to add services to the container.
         public void ConfigureServices(IServiceCollection services)
         {
+            var urls = Environment.GetEnvironmentVariable("ASPNETCORE_URLS");
             // true,默認情況下,聲明映射將以舊格式映射聲明名稱,以適應較早的SAML應用程序,RoleClaimType = 'http://schemas.microsoft.com/ws/2008/06/identity/claims/role'
             // false,RoleClaimType = 'roles'             
             JwtSecurityTokenHandler.DefaultMapInboundClaims = false;

+ 4 - 4
TEAMModelOS/TEAMModelOS.csproj

@@ -80,11 +80,11 @@
 		<SpaRoot>ClientApp\</SpaRoot>
 		<DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
 		<UserSecretsId>078b5d89-7d90-4f6a-88fc-7d96025990a8</UserSecretsId>
-		<Version>5.2408.7</Version>
-		<AssemblyVersion>5.2408.7.1</AssemblyVersion>
-		<FileVersion>5.2408.7.1</FileVersion>
+		<Version>5.2408.14</Version>
+		<AssemblyVersion>5.2408.14.1</AssemblyVersion>
+		<FileVersion>5.2408.14.1</FileVersion>
 		<Description>TEAMModelOS(IES5)</Description>
-		<PackageReleaseNotes>IES版本说明版本切换标记5.2408.7.1</PackageReleaseNotes>
+		<PackageReleaseNotes>IES版本说明版本切换标记5.2408.14.1</PackageReleaseNotes>
 		<PackageId>TEAMModelOS</PackageId>
 		<Authors>teammodel</Authors>
 		<Company>醍摩豆(成都)信息技术有限公司</Company>

+ 1 - 1
TEAMModelOS/appsettings.Development.json

@@ -18,7 +18,7 @@
     "IdTokenSalt": "8263692E2213497BB55E74792B7900B4",
     "HttpTrigger": "https://teammodelosfunction-test.chinacloudsites.cn/api/",
     //"HttpTrigger": "http://localhost:7071/api/"
-    "Version": "5.2408.7.1"
+    "Version": "5.2408.14.1"
   },
   "Azure": {
     // 测试站数据库

+ 1 - 1
TEAMModelOS/appsettings.json

@@ -18,7 +18,7 @@
     "Exp": 86400,
     "IdTokenSalt": "8263692E2213497BB55E74792B7900B4",
     "HttpTrigger": "https://teammodelosfunction.chinacloudsites.cn/api/",
-    "Version": "5.2408.7.1"
+    "Version": "5.2408.14.1"
   },
   "Azure": {
     "Storage": {