using Application.Domain.Entities; using Application.Models; using Infrastructure.Data; using Infrastructure.Domain; using Infrastructure.Events; using Infrastructure.Extensions; using Microsoft.AspNetCore.SignalR.Client; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Threading; using System.Threading.Tasks; namespace IoT.Shared.Services { public class IoTNodeClient : IHostedService, IDisposable { private string _notifyHost; private HubConnection Connection; private readonly IServiceProvider applicationServices; private readonly IConfiguration _cfg; public string ConnectionId { get; private set; } public IoTNodeClient(IServiceProvider applicationServices, IConfiguration configuration) { this.applicationServices = applicationServices; this._cfg = configuration; this.ConnectionId = Guid.NewGuid().ToBase62(); } public Task StartAsync(CancellationToken cancellationToken) { Task.Run(async () => { while (!cancellationToken.IsCancellationRequested) { this.Connect(); await Task.Delay(10 * 1000).ConfigureAwait(true); } }); return Task.CompletedTask; } public Task StopAsync(CancellationToken cancellationToken) { return Task.CompletedTask; } [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:不捕获常规异常类型", Justification = "<挂起>")] public void Connect() { if (this._cfg.GetValue("notify:enabled", false)) { Console.WriteLine("notify is enabled"); try { if (Connection == null) { Console.WriteLine("connection is null"); InitConnection(); } if (Connection.State == HubConnectionState.Disconnected) { Console.WriteLine("start connect"); if (this._notifyHost != this._cfg["notify:host"]) { InitConnection(); } Connection.StartAsync().Wait(); this.OnConnected(); } else { if (this._notifyHost != this._cfg["notify:host"]) { this.ReConnect(null); } else { Console.WriteLine($"connection has connected"); } } } catch (Exception ex) { ex.PrintStack(); } } else { Console.WriteLine("notify is disabled"); this.Close(); } } public void Close() { if (this.Connection != null) { if (this.Connection.State == HubConnectionState.Connected) { this.Connection.StopAsync(); } this.Connection.DisposeAsync(); this.Connection = null; } } private Task ReConnect(Exception arg) { this.Close(); this.Connect(); return Task.CompletedTask; } private void InitConnection() { this._notifyHost = this._cfg["notify:host"]; var url = $"http://{this._notifyHost}/hub?group={this._cfg["sn"]}"; Console.WriteLine($"init connection for {url}"); if (this.Connection != null) { this.Connection.DisposeAsync(); } this.Connection = new HubConnectionBuilder().WithUrl(url).Build(); this.Connection.Closed += ReConnect; this.Connection.On(Methods.ServerToClient, (string method, string message, string to, string from) => this.OnServerToClient(method, message, to, from)); } public void ServerToClient(string method, string message, string to, string from) { this.OnServerToClient(method, method, to, from); } [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:不捕获常规异常类型", Justification = "<挂起>")] public void ClientToServer(string method, object data, string to, string from = null) { Task.Run(() => { try { if (this.Connection != null && this.Connection.State == HubConnectionState.Connected) { this.Connection.SendAsync(Methods.ClientToServer, method, data.ToJson(), to, from ?? this._cfg["sn"]); } else { Console.WriteLine($"{_notifyHost} not connected"); } } catch (Exception ex) { ex.PrintStack(); } }); } public void Dispose() { this.Close(); } public void OnConnected() { Console.WriteLine($"{_notifyHost} OnConnected"); //上传节点 this.UpdateEntityIdList(null, Methods.UpdateNodeResponse); //上传产品 this.UpdateEntityIdList(null, Methods.UpdateProductResponse); //上传接口 this.UpdateEntityIdList(null, Methods.UpdateApiResponse); //上传参数 this.UpdateEntityIdList(null, Methods.UpdateParameterResponse); //上传设备Id列表、设备 this.UpdateEntityIdList(Methods.UpdateDeviceIdListResponse, Methods.UpdateDeviceResponse); //上传数据 this.UpdateEntityIdList(null, Methods.UpdateDataResponse, null, o => !o.Hidden); //上传命令Id列表、命令 this.UpdateEntityIdList(Methods.UpdateCommandIdListResponse, Methods.UpdateCommandResponse); //上传场景Id列表、场景 this.UpdateEntityIdList(Methods.UpdateSceneIdListResponse, Methods.UpdateSceneResponse); //上传定时器Id列表、定时器 this.UpdateEntityIdList(Methods.UpdateIoTTimerIdListResponse, Methods.UpdateIoTTimerResponse); //上传触发器Id列表、触发器 this.UpdateEntityIdList(Methods.UpdateIoTTiggerIdListResponse, Methods.UpdateIoTTiggerResponse); //上传场景命令Id列表、场景命令 this.UpdateEntityIdList(Methods.UpdateSceneCommandIdListResponse, Methods.UpdateSceneCommandResponse); //上传定时器命令Id列表、定时器命令 this.UpdateEntityIdList(Methods.UpdateIoTTimerCommandIdListResponse, Methods.UpdateIoTTimerCommandResponse); //上传触发器命令Id列表、触发器命令 this.UpdateEntityIdList(Methods.UpdateIoTTiggerCommandIdListResponse, Methods.UpdateIoTTiggerCommandResponse); } [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:不捕获常规异常类型", Justification = "<挂起>")] public void OnServerToClient(string method, string message, string to, string from) { try { using var scope = this.applicationServices.CreateScope(); var dataService = scope.ServiceProvider.GetService(); var eventPublisher = scope.ServiceProvider.GetService(); if (method == "UpdateNode") { this.OnConnected(); } else if (method == $"Edit{nameof(Node)}")//服务端编辑节点 { var model = message.FromJson(); dataService.Edit(model); this.ClientToServer(method, model, null); } else if (method == $"Edit{nameof(Device)}")//服务端编辑设备 { var model = message.FromJson(); dataService.Edit(model); this.ClientToServer(method, model, null); } else if (method == $"Delete{nameof(Device)}")//服务端删除设备 { var model = message.FromJson(); dataService.Delete(model); this.ClientToServer(method, model, null); } else if (method == $"Edit{nameof(Data)}")//服务端编辑数据 { var model = message.FromJson(); dataService.Edit(model); this.ClientToServer(method, model, null); } else if (method == $"Delete{nameof(Data)}")//服务端删除数据 { var model = message.FromJson(); dataService.Delete(model); this.ClientToServer(method, model, null); } else if (method == $"Edit{nameof(Command)}")//服务端编辑命令 { var model = message.FromJson(); dataService.Edit(model); this.ClientToServer(method, model, null); } else if (method == $"Delete{nameof(Command)}")//服务端删除命令 { var model = message.FromJson(); dataService.Delete(model); this.ClientToServer(method, model, null); } else if (method == $"Edit{nameof(Scene)}")//服务端编辑场景 { var model = message.FromJson(); dataService.Edit(model); this.ClientToServer(method, model, null); } else if (method == $"Delete{nameof(Scene)}")//服务端删除场景 { var model = message.FromJson(); dataService.Delete(model); this.ClientToServer(method, model, null); } else if (method == $"Edit{nameof(IoTTimer)}") { var model = message.FromJson(); dataService.Edit(model); this.ClientToServer(method, model, null); } else if (method == $"Delete{nameof(IoTTimer)}") { var model = message.FromJson(); dataService.Delete(model); this.ClientToServer(method, model, null); } else if (method == $"Edit{nameof(IoTTigger)}") { var model = message.FromJson(); dataService.Edit(model); this.ClientToServer(method, model, null); } else if (method == $"Delete{nameof(IoTTigger)}") { var model = message.FromJson(); dataService.Delete(model); this.ClientToServer(method, model, null); } else if (method == $"Edit{nameof(SceneCommand)}") { var model = message.FromJson(); dataService.Edit(model); this.ClientToServer(method, model, null); } else if (method == $"Delete{nameof(SceneCommand)}") { var model = message.FromJson(); dataService.Delete(model); this.ClientToServer(method, model, null); } else if (method == $"Edit{nameof(IoTTimerCommand)}") { var model = message.FromJson(); dataService.Edit(model); this.ClientToServer(method, model, null); } else if (method == $"Delete{nameof(IoTTimerCommand)}") { var model = message.FromJson(); dataService.Delete(model); this.ClientToServer(method, model, null); } else if (method == $"Edit{nameof(IoTTiggerCommand)}") { var model = message.FromJson(); dataService.Edit(model); this.ClientToServer(method, model, null); } else if (method == $"Delete{nameof(IoTTiggerCommand)}") { var model = message.FromJson(); dataService.Delete(model); this.ClientToServer(method, model, null); } else if (method == Methods.ExecApiRequest) { var cfg = scope.ServiceProvider.GetService(); var port = cfg["server.urls"].Split(':')[2]; var url = $"http://localhost:{port}{message.FromJson()}"; var httpClient = scope.ServiceProvider.GetService().CreateClient(); var result = httpClient.GetStringAsync(url).Result; this.ClientToServer(Methods.ExecApiResponse, result, from); } else if (method == Methods.ExecSceneRequest) { var sceneId = message.FromJson(); var sceneCommandRepo = scope.ServiceProvider.GetService>(); var commands = sceneCommandRepo.ReadOnlyTable() .Where(o => o.SceneId == sceneId) .Include(o => o.Command).ThenInclude(o => o.Api) .Include(o => o.Command).ThenInclude(o => o.Device) .Select(o => o.Command) .ToList(); this.ExecCommands(commands); this.ClientToServer(Methods.ExecSceneRsponse, null, from); } /////////////////////////////////////////////////////////// else if (method == Methods.ExecCommand) { var id = message.FromJson(); this.ExecCommand(id); } else if (method == Methods.UpdateCamera) { var model = message.FromJson(); dataService.Edit(model); this.ClientToServer("EditData", model, null); } } catch (Exception ex) { ex.PrintStack(); } } public void ExecCommand(Guid id) { using var scope = this.applicationServices.CreateScope(); var commandRepo = scope.ServiceProvider.GetService>(); var command = commandRepo.ReadOnlyTable().Include(o => o.Device).Include(o => o.Api).FirstOrDefault(o => o.Id == id); if (command != null) { try { var cfg = scope.ServiceProvider.GetService(); var port = cfg["server.urls"].Split(':')[2]; var url = this.GetCommandUrl(command); var httpClient = scope.ServiceProvider.GetService().CreateClient(); var result = httpClient.GetStringAsync(url).Result; } catch (Exception ex) { ex.PrintStack(); } } } public void ExecCommands(List commands) { using var scope = this.applicationServices.CreateScope(); foreach (var command in commands) { try { var cfg = scope.ServiceProvider.GetService(); var port = cfg["server.urls"].Split(':')[2]; var url = this.GetCommandUrl(command); var httpClient = scope.ServiceProvider.GetService().CreateClient(); var result = httpClient.GetStringAsync(url).Result; } catch (Exception ex) { ex.PrintStack(); } } } private string GetCommandUrl(Command command) { using var scope = this.applicationServices.CreateScope(); var cfg = scope.ServiceProvider.GetService(); var port = cfg["server.urls"].Split(':')[2]; var url = $"http://localhost:{port}{command.Api.Path}{command.Api.Command}?number={command.Device.Number}{(string.IsNullOrEmpty(command.QueryString) ? "" : "&")}{command.QueryString}"; return url; } private void UpdateEntityIdList(string updateIdListMethod, string updateEntityMethod, Func, IQueryable> include = null, Func predicate = null) where T : BaseEntity { using var scope = this.applicationServices.CreateScope(); var repo = scope.ServiceProvider.GetService>(); var query = repo.ReadOnlyTable(); if (include != null) { query = include(query); } if (predicate != null) { query = query.Where(predicate).AsQueryable(); } var entities = query.ToList(); if (!string.IsNullOrEmpty(updateIdListMethod)) { this.ClientToServer(updateIdListMethod, entities.Select(o => o.Id).ToList(), null); } if (!string.IsNullOrEmpty(updateEntityMethod)) { foreach (var entity in entities) { this.ClientToServer(updateEntityMethod, entity, null); } } } [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:不捕获常规异常类型", Justification = "<挂起>")] public string GetApiJson(string prefix) { try { using var scope = applicationServices.CreateScope(); var serviceProvider = scope.ServiceProvider; var cfg = serviceProvider.GetService(); var port = cfg["server.urls"].Split(':')[2]; var url = $"http://localhost:{port}/swagger/v1/swagger.json"; var hc = serviceProvider.GetService().CreateClient(); var result = hc.GetStringAsync(url).Result; var json = JsonConvert.DeserializeObject(result) as JObject; var paths = json.Properties().FirstOrDefault(o => o.Name == "paths").Value as JObject; var names = paths.Properties().Select(o => o.Name).ToList(); foreach (var item in names) { if (!item.StartsWith(prefix)) { paths.Remove(item); } } var tags = json.Properties().FirstOrDefault(o => o.Name == "tags").Value as JArray; var names2 = tags.Select(o => (o as JObject).Properties().FirstOrDefault(o => o.Name == "name").Value.ToString()).ToList(); foreach (var item in names2) { if (item != prefix.Trim('/')) { tags.Remove(tags.FirstOrDefault(o => (o as JObject).Properties().FirstOrDefault(o => o.Name == "name").Value.ToString() != prefix.Trim('/'))); } } var realResult = JsonConvert.SerializeObject(json); return realResult; } catch (Exception ex) { ex.PrintStack(); return null; } } } }