using System; using System.Linq; using System.Net.Http; using Application.Domain.Entities; using Infrastructure.Data; using Infrastructure.Extensions; using Infrastructure.Models; using IoTShared; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.SignalR; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using Microsoft.OpenApi.Readers; namespace IoTNode.Controllers { public class NotifyController : Controller { private readonly static object thisLock = new object(); private readonly ILogger _logger; private readonly IConfiguration _configuration; private readonly IHttpContextAccessor _httpContextAccessor; private readonly IHttpClientFactory _httpClientFactory; private readonly IHubContext _pageHubContext; private readonly IRepository _nodeRepo; private readonly IRepository _deviceRepo; private readonly IRepository _senceRepo; public NotifyController(ILogger logger, IConfiguration configuration, IHttpContextAccessor httpContextAccessor, IHttpClientFactory httpClientFactory, IHubContext pageHubContext, IRepository nodeRepo, IRepository deviceRepo, IRepository senceRepo) { this._logger = logger; this._configuration = configuration; this._httpContextAccessor = httpContextAccessor; this._httpClientFactory = httpClientFactory; this._pageHubContext = pageHubContext; this._nodeRepo = nodeRepo; this._deviceRepo = deviceRepo; this._senceRepo = senceRepo; } public IActionResult Index(NotifyModel model) { if (ModelState.IsValid) { var device = this._deviceRepo.Table() .Include(o => o.Data) .Include(o => o.Apis).ThenInclude(o => o.Parameters) .FirstOrDefault(o => o.Number == model.Number); var node = this._nodeRepo.ReadOnlyTable().FirstOrDefault(); try { if (node == null) { node = new Node { Name = this._configuration["name"], Number = Helper.Instance.GetMacAddress() }; this._nodeRepo.Add(node); this._nodeRepo.SaveChanges(); } if (device == null) { device = new Device { NodeId = node.Id, DisplayName = model.Name }; this._deviceRepo.Add(device); } UpdateDeviceFromModel(device, model); this._deviceRepo.SaveChanges(); device.Node = node; UpdatePage(device); this.SendDeviceDataToServer(device); return new JsonResult("Succeed"); } catch (Exception ex) { ex.PrintStack(); return new JsonResult(ex.Message); } } return new JsonResult(new { message = "invalid", model }); } private void UpdateDeviceFromModel(Device device, NotifyModel model) { if (model.Data.Count > 0) { //foreach (var key in device.Data.Select(o => o.Key).ToList()) //{ // if (!model.Data.Any(o => o.Key == key)) // { // var data = device.Data.FirstOrDefault(o => o.Key == key); // device.Data.Remove(data); // } //} foreach (var newData in model.Data) { var data = device.Data.FirstOrDefault(o => o.Key == newData.Key); if (data == null) { data = new Data(); device.Data.Add(data); } data.FromPlain(newData); data.Timestamp = model.Timestamp; } } if (string.IsNullOrEmpty(device.ApiJson)) { var url = model.BaseUrl + model.ApiPath; Console.WriteLine($"notify>api url:{url}"); var task = this._httpClientFactory.CreateClient().GetAsync(url); task.Wait(); using (var result = task.Result) { using (var content = result.Content) { device.ApiJson = content.ReadAsStringAsync().Result; this.UpdateApi(device); } } } device.FromPlain(model); } private void UpdateApi(Device device) { var reader = new OpenApiStringReader(new OpenApiReaderSettings { }).Read(device.ApiJson, out OpenApiDiagnostic diagnostic); foreach (var path in reader.Paths) { foreach (var operation in path.Value.Operations) { if (!device.Apis.Any(o => o.Name == operation.Value.Summary)) { var postion = path.Key.LastIndexOf('/') + 1; var api = new Api { Path = path.Key.Substring(0, postion), Command = path.Key.Substring(postion), Name = operation.Value.Summary, Method = operation.Key.ToString() }; device.Apis.Add(api); foreach (var name in api.Parameters.Select(o => o.Name).ToList()) { if (operation.Value.Parameters.Any(o => o.Name == name)) { var parameter = api.Parameters.FirstOrDefault(o => o.Name == name); api.Parameters.Remove(parameter); } } foreach (var parameter in operation.Value.Parameters.Where(o => o.Name != "id")) { if (!api.Parameters.Any(o => o.Name == parameter.Name)) { api.Parameters.Add(new Parameter { Name = parameter.Name, Description = parameter.Description, Required = parameter.Required, Type = parameter.Schema.Type, Minimum = parameter.Schema.Minimum?.ToString(), Maxinum = parameter.Schema.Maximum?.ToString() }); } } } } } } private void UpdatePage(Device device) { var data = device.ToJson(); this._pageHubContext.Clients.Group("page").SendAsync("UpdateDevice", data); } private void SendDeviceDataToServer(Device device) { if (!this._configuration.GetValue("notify:enabled")) { return; } var schoolUrl = $"http://{this._configuration["notify:host"]}/Notify"; var data = device.ToJson(); try { var task = this._httpClientFactory.CreateClient().PostAsync(schoolUrl, new StringContent(data)); task.Wait(); using (var response = task.Result) { using (var content = response.Content) { var result = content.ReadAsStringAsync().Result; Console.WriteLine($"server response:{schoolUrl}:{result}"); } } } catch (Exception ex) { ex.PrintStack(); } } } }