123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253 |
-
- using Azure.Storage.Blobs;
- using Azure.Storage.Blobs.Models;
- using Microsoft.AspNetCore.Hosting.Server;
- using Microsoft.AspNetCore.Hosting.Server.Features;
- using Microsoft.AspNetCore.SignalR.Client;
- using Microsoft.Extensions.Configuration;
- using System.Diagnostics;
- using System.Management;
- using System.Net;
- using System.Net.Http.Headers;
- using System.Net.NetworkInformation;
- using System.Runtime.InteropServices;
- using System.Text;
- using System.Text.Json;
- using System.Text.Json.Nodes;
- using System.Text.RegularExpressions;
- using System.Threading.Tasks;
- using System.Web;
- using TEAMModelOS.SDK;
- using TEAMModelOS.SDK.DI.Device;
- using TEAMModelOS.SDK.Extension;
- namespace HTEX.ScreenClient.Services
- {
- public class SignalRScreenClientHub : BackgroundService, IDisposable
- {
- private readonly IConfiguration _configuration;
- private readonly ILogger<SignalRScreenClientHub> _logger;
- private TEAMModelOS.SDK.ScreenClient? device;
- private readonly CoreDevice _device;
- private readonly IHttpClientFactory _httpClientFactory;
- public SignalRScreenClientHub(IConfiguration configuration,ILogger<SignalRScreenClientHub> logger,IHttpClientFactory httpClientFactory, CoreDevice device)
- {
-
- _configuration=configuration;
- _logger=logger;
- _httpClientFactory=httpClientFactory;
- _device = device;
- }
-
- protected async override Task ExecuteAsync(CancellationToken stoppingToken)
- {
- var coreDevice = await _device.GetCoreDevice();
- device=coreDevice.ToJsonString().ToObject<TEAMModelOS.SDK.ScreenClient>();
- string clientid = device.deviceId!;
- 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;
- await StartHubConnectionAsync( clientid, CenterUrl);
- }
- private async Task StartHubConnectionAsync(string clientid, string? CenterUrl)
- {
- //重写重连策略,防止服务端更新,断线后,客户端达到最大连接次数,依然连线不上服务端。
- var reconnectPolicy = new ExponentialBackoffReconnectPolicy(TimeSpan.FromSeconds(10), _logger); // 尝试重连的最大次数,这里使用 int.MaxValue 表示无限次
- reconnectPolicy.MaxRetryCount = int.MaxValue;
- HubConnection hubConnection = new HubConnectionBuilder()
- .WithUrl($"{CenterUrl}/signalr/screen?grant_type={ScreenConstant.grant_type}&clientid={clientid}&device={HttpUtility.UrlEncode(device.ToJsonString(), Encoding.Unicode)}") //only one slash
- .WithAutomaticReconnect(reconnectPolicy)
- .ConfigureLogging(logging =>
- {
- logging.SetMinimumLevel(LogLevel.Information);
- logging.AddConsole();
- })
- .Build();
- try {
- hubConnection.On<ConnectionMessage>("ReceiveConnection", (message) =>
- {
- _logger.LogInformation($"连接成功:{message.ToJsonString()}");
- //重置重连次数。
- reconnectPolicy.Reset();
- });
- hubConnection.On<ScreenProcessMessage>("ReceiveMessage", async (message) =>
- {
- if (message.message_type.Equals(MessageType.task_send_success))
- {
- var data = await ReceiveMessage(message);
- _logger.LogInformation($"任务执行完成,执行状态{data.status},消息:{data.msg},任务信息:{data.task?.ToJsonString()}");
- message.content=data.task?.ToJsonString();
- message.result=data.status;
- message.msg=data.msg;
- if (data.status==2)
- {
- message.message_type= MessageType.task_execute_success;
- }
- else
- {
- message.message_type= MessageType.task_execute_error;
- }
- await hubConnection.InvokeAsync<ScreenProcessMessage>("ReceiveMessage", message);
- }
- else
- {
- _logger.LogInformation($"任务领取失败,{message.ToJsonString()}");
- }
- });
- await hubConnection.StartAsync();
- }
- catch (Exception ex)
- {
- _logger.LogError("初次启动连接SignalR失败,等待重连......");
- int retryCount = 0;
- const int maxRetries = 360;
- const int retryDelaySeconds = 10;
- while (retryCount < maxRetries)
- {
- try
- {
- await Task.Delay(retryDelaySeconds * 1000); // 等待一段时间后重试
- await hubConnection.StartAsync();
- _logger.LogInformation("SignalR连接成功(重试后)!");
- break; // 连接成功,退出循环
- }
- catch (Exception retryEx)
- {
- retryCount++;
- _logger.LogInformation($"SignalR连接重试失败: {retryEx.Message}。重试次数: {retryCount}/{maxRetries}");
- // 可以在这里决定是否因为某种原因停止重试
- if (retryCount == maxRetries)
- {
- _logger.LogInformation("达到最大重试次数,停止重试。");
- break;
- }
- }
- }
- }
- }
- public async Task<(int status, string msg, PDFGenQueue? task )> ReceiveMessage(ScreenProcessMessage message)
- {
- int status = 0;
- string msg= string.Empty;
- PDFGenQueue? task = null;
- try
- {
- task = message.content.ToObject<PDFGenQueue>();
- long now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
- var client = _httpClientFactory.CreateClient();
- string urlpdf = $"{device.screenUrl}/api/pdf";
- string jsonElement = new
- {
- pageUrl = task.pageUrl,
- timeout = task.timeout,
- delay = task.delay,
- checkPageCompleteJs = task.checkPageCompleteJs
- }.ToJsonString();
- var request = new HttpRequestMessage
- {
- Method = new HttpMethod("POST"),
- RequestUri = new Uri(urlpdf),
- Content = new StringContent(jsonElement)
- };
- var mediaTypeHeader = new MediaTypeHeaderValue("application/json")
- {
- CharSet = "UTF-8"
- };
- request.Content.Headers.ContentType = mediaTypeHeader;
- HttpResponseMessage responseMessage = await client.SendAsync(request);
- if (responseMessage.IsSuccessStatusCode)
- {
- string content = await responseMessage.Content.ReadAsStringAsync();
- JsonNode jsonNode = content.ToObject<JsonNode>();
- var code = jsonNode["code"];
- var file = jsonNode["data"]?["file"];
- if (code!=null && $"{code}".Equals("0") && file!= null && !string.IsNullOrWhiteSpace($"{file}"))
- {
- try
- {
- Stream stream = await client.GetStreamAsync($"{device.screenUrl}/{file}");
- string content_type = "application/octet-stream";
- ContentTypeDict.dict.TryGetValue(".pdf", out string? contenttype);
- if (!string.IsNullOrEmpty(contenttype))
- {
- content_type = contenttype;
- }
- BlobClient blockBlob = new BlobClient(new Uri(task.blobFullUrl));
- await blockBlob.UploadAsync(stream, true);
- blockBlob.SetHttpHeaders(new BlobHttpHeaders { ContentType = content_type });
- status=2;
- msg = $"PDF回传保存成功!保存地址{task.blobFullUrl}";
- }
- catch (Exception ex) {
- status=6;
- msg = $"PDF回传保存异常!异常信息{ex.Message},相关参数信息:保存地址{task.blobFullUrl}";
- }
- }
- else {
- if (code!= null && $"{code}".Equals("99999"))
- {
- status= 4;
- msg = "PDF生成接口调用超时!";
- }
- else
- {
- status= 3;
- msg =$"PDF生成接口返回参数异常!返回内容:{content}";
- }
- }
- }
- else {
- status=3;
- msg =$"PDF生成接口调用异常!接口状态:{responseMessage.StatusCode}";
- }
- }
- catch (Exception ex)
- {
- status = 3;
- msg = $"PDF生成接口调用异常,异常信息“{ex.Message}";
- }
- return (status, msg, task);
- }
-
-
- }
- public class ExponentialBackoffReconnectPolicy : IRetryPolicy
- {
- private readonly TimeSpan _retryInterval;
-
- private int _retryCount;
- public int MaxRetryCount { get; set; } =int.MaxValue;
- public readonly ILogger<SignalRScreenClientHub> _logger;
- public ExponentialBackoffReconnectPolicy(TimeSpan retryInterval, ILogger<SignalRScreenClientHub> logger)
- {
- _retryInterval = retryInterval;
- _retryCount = 0;
- _logger = logger;
- }
- public TimeSpan? NextRetryDelay(RetryContext retryContext)
- {
- _logger.LogInformation($"重连次数: {_retryCount}");
- if (_retryCount < MaxRetryCount)
- {
- _retryCount++;
- // 计算下一次重连的延迟时间
- return _retryInterval;
- }
- return null; // 达到最大重连次数后不再重连
- }
- public void Reset()
- {
- _retryCount = 0;
- }
- }
- }
|