You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
iot/projects/IoT/IoT.Shared/Application/Services/NodeService.cs

678 lines
25 KiB

using Application.Domain.Entities;
using Application.Models;
using Infrastructure.Data;
using Infrastructure.Extensions;
using Infrastructure.Web.SignalR;
using Microsoft.AspNetCore.SignalR;
using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
namespace Application.Services
{
public class NodeService : INodeService, IDisposable
{
private IServiceProvider applicationServices;
private readonly IConfiguration _cfg;
private CancellationTokenSource _tokenSource;
public HubConnection Connection;
private string _notifyHost;
public NodeService(IServiceProvider applicationServices, IConfiguration configuration)
{
this.applicationServices = applicationServices;
this._cfg = configuration;
this._tokenSource = new CancellationTokenSource();
}
public bool IsCallback { get; set; }
public bool EditNode(EditNodeModel model)
{
try
{
using (var scope = applicationServices.CreateScope())
{
var repo = scope.ServiceProvider.GetService<IRepository<Node>>();
var entity = repo.Table().FirstOrDefault(o => o.Id == model.Id);
entity.Name = model.Name;
if (repo.SaveChanges() > 0)
{
this.SendToPage(scope, $"page", "UpdateNode", entity.ToJson());
this.UpdateServer(nameof(INodeService.EditNode), model);
}
return true;
}
}
catch (Exception ex)
{
ex.PrintStack();
return false;
}
}
public bool DeleteNode(Guid id)
{
try
{
using (var scope = applicationServices.CreateScope())
{
var repo = scope.ServiceProvider.GetService<IRepository<Node>>();
var entity = repo.Table().FirstOrDefault(o => o.Id == id);
repo.Delete(entity);
if (repo.SaveChanges() > 0)
{
this.SendToPage(scope, $"page", "DeleteNode", entity.ToJson());
this.UpdateServer(nameof(INodeService.DeleteNode), id);
}
return true;
}
}
catch (Exception ex)
{
ex.PrintStack();
return false;
}
}
public bool EditDevice(EditDeviceModel model)
{
try
{
using (var scope = applicationServices.CreateScope())
{
var repo = scope.ServiceProvider.GetService<IRepository<Device>>();
var entity = repo.Table().FirstOrDefault(o => o.Id == model.Id);
entity.DisplayName = model.DisplayName;
if (repo.SaveChanges() > 0)
{
var device = repo.ReadOnlyTable()
.Include(o => o.Node)
.Include(o => o.Data)
.Include(o => o.Apis).ThenInclude(o => o.Parameters)
.FirstOrDefault(o => o.Id == entity.Id);
this.SendToPage(scope, $"node-{device.Node.Number}", "UpdateDevice", device.ToJson());
this.UpdateServer(nameof(INodeService.EditDevice), model);
}
return true;
}
}
catch (Exception ex)
{
ex.PrintStack();
return false;
}
}
public bool DeleteDevice(Guid id)
{
try
{
using (var scope = applicationServices.CreateScope())
{
var repo = scope.ServiceProvider.GetService<IRepository<Device>>();
var entity = repo.Table().FirstOrDefault(o => o.Id == id);
if (entity != null)
{
var nodeRepo = scope.ServiceProvider.GetService<IRepository<Node>>();
var number = nodeRepo.ReadOnlyTable().FirstOrDefault(o => o.Id == entity.NodeId).Number;
repo.Delete(entity);
if (repo.SaveChanges() > 0)
{
this.SendToPage(scope, $"node-{number}", "DeleteDevice", entity.Number);
this.UpdateServer(nameof(INodeService.DeleteDevice), id);
}
}
return true;
}
}
catch (Exception ex)
{
ex.PrintStack();
return false;
}
}
public bool CreateSence(EditSenceModel model)
{
try
{
using (var scope = applicationServices.CreateScope())
{
var repo = scope.ServiceProvider.GetService<IRepository<Sence>>();
var entity = new Sence().From(model);
repo.Add(entity);
if (repo.SaveChanges() > 0)
{
var nodeRepo = scope.ServiceProvider.GetService<IRepository<Node>>();
var number = nodeRepo.ReadOnlyTable().FirstOrDefault(o => o.Id == entity.NodeId).Number;
this.SendToPage(scope, $"page", "UpdateSence", entity.ToJson());
this.UpdateServer(nameof(INodeService.CreateSence), model);
}
return true;
}
}
catch (Exception ex)
{
ex.PrintStack();
return false;
}
}
public bool EditSence(EditSenceModel model)
{
try
{
using (var scope = applicationServices.CreateScope())
{
var repo = scope.ServiceProvider.GetService<IRepository<Sence>>();
var entity = repo.Table().FirstOrDefault(o => o.Id == model.Id);
entity.From(model);
if (repo.SaveChanges() > 0)
{
var nodeRepo = scope.ServiceProvider.GetService<IRepository<Node>>();
var number = nodeRepo.ReadOnlyTable().FirstOrDefault(o => o.Id == entity.NodeId).Number;
this.SendToPage(scope, $"page", "UpdateSence", entity.ToJson());
this.UpdateServer(nameof(INodeService.EditSence), model);
}
return true;
}
}
catch (Exception ex)
{
ex.PrintStack();
return false;
}
}
public bool DeleteSence(Guid id)
{
try
{
using (var scope = applicationServices.CreateScope())
{
var repo = scope.ServiceProvider.GetService<IRepository<Sence>>();
var entity = repo.Table().FirstOrDefault(o => o.Id == id);
if (entity != null)
{
var nodeRepo = scope.ServiceProvider.GetService<IRepository<Node>>();
var number = nodeRepo.ReadOnlyTable().FirstOrDefault(o => o.Id == entity.NodeId).Number;
repo.Delete(entity);
if (repo.SaveChanges() > 0)
{
this.SendToPage(scope, $"page", "DeleteSence", id.ToString());
this.UpdateServer(nameof(INodeService.DeleteSence), id);
}
}
return true;
}
}
catch (Exception ex)
{
ex.PrintStack();
return false;
}
}
public bool CreateCommand(EditCommandModel model)
{
try
{
using (var scope = applicationServices.CreateScope())
{
var repo = scope.ServiceProvider.GetService<IRepository<Command>>();
var entity = new Command().From(model);
entity.QueryString = model.GetQueryString();
repo.Add(entity);
if (repo.SaveChanges() > 0)
{
this.UpdateServer(nameof(INodeService.CreateCommand), model);
}
return true;
}
}
catch (Exception ex)
{
ex.PrintStack();
return false;
}
}
public bool EditCommand(EditCommandModel model)
{
try
{
using (var scope = applicationServices.CreateScope())
{
var repo = scope.ServiceProvider.GetService<IRepository<Command>>();
var entity = repo.Table().FirstOrDefault(o => o.Id == model.Id);
entity.From(model);
entity.QueryString = model.GetQueryString();
if (repo.SaveChanges() > 0)
{
this.UpdateServer(nameof(INodeService.EditCommand), model);
}
return true;
}
}
catch (Exception ex)
{
ex.PrintStack();
return false;
}
}
public bool DeleteCommand(Guid id)
{
try
{
using (var scope = applicationServices.CreateScope())
{
var repo = scope.ServiceProvider.GetService<IRepository<Command>>();
var entity = repo.Table().FirstOrDefault(o => o.Id == id);
if (entity != null)
{
repo.Delete(entity);
if (repo.SaveChanges() > 0)
{
this.UpdateServer(nameof(INodeService.DeleteCommand), id);
}
}
return true;
}
}
catch (Exception ex)
{
ex.PrintStack();
return false;
}
}
public ApiResponse Exec(Guid id, string cmd, string query)
{
try
{
using (var scope = applicationServices.CreateScope())
{
var deviceRepo = scope.ServiceProvider.GetService<IRepository<Device>>();
var device = deviceRepo.ReadOnlyTable().Include(o => o.Apis).Include(o => o.Data).FirstOrDefault(o => o.Id == id);
if (device.Name == "主机" && cmd == "21boot")
{
this.BootStrapPCByMacAddress(device.Number);
return ApiResponse.AsyncSuccess();
}
var url = $"{device.BaseUrl}/{cmd}{query}";
url = url.SetParam("id", device.Number);
if (device.Name == "红外转发器")
{
var api = device.Apis.FirstOrDefault(o => o.Command == cmd);
var keySets = device.Data.FirstOrDefault(o => o.Key == "hidden")?.Value ?? "";
var array = JsonConvert.DeserializeObject<List<IrDataModel>>(keySets) ?? new List<IrDataModel>();
if (cmd == "26add" || cmd == "25update" || cmd == "24delete")
{
var values = HttpUtility.ParseQueryString(query);
if (cmd == "26add")
{
var code = values.Get("newcode");
var name = values.Get("name");
if (!array.Any(o => o.code == code))
{
array.Add(new IrDataModel { code = code, name = name, irType = "00", status = "0", keyset = code });
}
}
else if (cmd == "25update")
{
var code = values.Get("code");
var name = values.Get("name");
var item = array.FirstOrDefault(o => o.code == code);
if (item != null)
{
item.name = name;
}
}
else if (cmd == "24delete")
{
}
url = url.SetParam("hidden", array.ToJson());
}
}
return ExecUrl(scope, url);
}
}
catch (Exception ex)
{
ex.PrintStack();
return ApiResponse.Error(ex);
}
}
public ApiResponse Sence(Guid id)
{
try
{
using (var scope = applicationServices.CreateScope())
{
var httpClientFactory = scope.ServiceProvider.GetService<IHttpClientFactory>();
var senceRepo = scope.ServiceProvider.GetService<IRepository<Sence>>();
var sence = senceRepo.ReadOnlyTable()
.Include(o => o.Commands)
.ThenInclude(o => o.Api)
.ThenInclude(o => o.Device)
.FirstOrDefault(o => o.Id == id);
foreach (var item in sence.Commands)
{
var device = item.Api.Device;
var url = $"{device.BaseUrl}/{item.Api.Command}?id={device.Number}";
if (!string.IsNullOrEmpty(item.QueryString))
{
url += $"&{item.QueryString}";
}
Console.WriteLine($"start:{url}");
var task = httpClientFactory.CreateClient().GetAsync(url);
task.Wait();
using (var response = task.Result)
{
using (var content = response.Content)
{
var result = content.ReadAsStringAsync().Result;
Console.WriteLine($"end:{url}:{result}");
}
}
}
}
return ApiResponse.AsyncSuccess();
}
catch (Exception ex)
{
ex.PrintStack();
return ApiResponse.Error(ex);
}
}
public ApiResponse ExecAll(List<Guid> id, string cmd, string query)
{
try
{
using (var scope = applicationServices.CreateScope())
{
foreach (var deviceId in id)
{
this.Exec(deviceId, cmd, query);
}
}
return ApiResponse.AsyncSuccess();
}
catch (Exception ex)
{
ex.PrintStack();
return ApiResponse.Error(ex);
}
}
private ApiResponse ExecUrl(IServiceScope scope, string url)
{
Console.WriteLine($"start:{url}");
var httpClientFactory = scope.ServiceProvider.GetService<IHttpClientFactory>();
var task = httpClientFactory.CreateClient().GetAsync(url);
task.Wait();
using (var response = task.Result)
{
using (var content = response.Content)
{
var value = content.ReadAsStringAsync().Result;
Console.WriteLine($"end:{url}:{value}");
var result = value.FromJson<ApiResponse>();
return result;
}
}
}
private void BootStrapPCByMacAddress(string mac)
{
var message = "";
for (int i = 0; i < 12; i++)
{
message += "f";
}
for (int i = 0; i < 16; i++)
{
message += mac;
}
var data = message.HexToBytes();
using (var client = new UdpClient(new IPEndPoint(IPAddress.Broadcast, 0)))
{
client.Send(data, data.Length, new IPEndPoint(IPAddress.Parse("255.255.255.255"), 9));
}
Console.WriteLine("boot");
}
private void SendToPage(IServiceScope scope, string group, string method, string data)
{
try
{
var hc = scope.ServiceProvider.GetService<IHubContext<PageHub>>();
hc.Clients.Group(group).SendAsync(method, data);
}
catch (Exception ex)
{
ex.PrintStack();
}
}
private void UpdateServer(string method, object model)
{
if (!this.IsCallback)
{
try
{
using (var scope = applicationServices.CreateScope())
{
var configuration = scope.ServiceProvider.GetService<IConfiguration>();
if (configuration.GetValue<bool>("notify:enabled"))
{
this.Connection.SendAsync("UpdateCallBack", method, model.ToJson());
}
}
}
catch (Exception ex)
{
ex.PrintStack();
}
}
}
public void Notify()
{
try
{
using (var scope = applicationServices.CreateScope())
{
var configuration = scope.ServiceProvider.GetService<IConfiguration>();
if (configuration.GetValue<bool>("notify:enabled"))
{
Console.WriteLine("PushSenceAndDevice");
var schoolUrl = $"http://{configuration["notify:host"]}/Notify/Update";
var nodeRepo = scope.ServiceProvider.GetService<IRepository<Node>>();
var node = nodeRepo.ReadOnlyTable().Include(o => o.Sences).Include(o => o.Devices).FirstOrDefault();
var data = node.ToJson();
var httpClientFactory = scope.ServiceProvider.GetService<IHttpClientFactory>();
var task = 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();
}
}
public void Start()
{
Task.Run(async () =>
{
while (!_tokenSource.IsCancellationRequested)
{
this.Connect();
await Task.Delay(this._cfg.GetValue<int>("timer.seconds", 60) * 1000);
}
});
}
public void Connect()
{
if (this._cfg.GetValue<bool>("notify: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.Notify();
}
else
{
if (this._notifyHost != this._cfg["notify:host"])
{
this.ReConnect(null);
}
else
{
Console.WriteLine($"connection is connected");
}
}
}
catch (Exception ex)
{
ex.PrintStack();
}
}
}
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 = "";
using (var scope = applicationServices.CreateScope())
{
var repo = scope.ServiceProvider.GetService<IRepository<Node>>();
var nodeNumber = repo.ReadOnlyTable().FirstOrDefault().Number;
url = $"http://{this._notifyHost}/hub?group={nodeNumber}";
}
this.Connection = new HubConnectionBuilder().WithUrl(url).Build();
this.Connection.Closed += ReConnect;
this.Connection.On(nameof(Exec), (string connectionId, Guid id, string cmd, string query) =>
{
var response = this.Exec(id, cmd, query);
this.Connection.SendAsync("Send", connectionId, "ApiResult", response.ToJson());
});
this.Connection.On(nameof(ExecAll), (string connectionId, List<Guid> id, string cmd, string query) =>
{
var response = this.ExecAll(id, cmd, query);
this.Connection.SendAsync("Send", connectionId, "ApiResult", response.ToJson());
});
this.Connection.On(nameof(Sence), (string connectionId, Guid id) =>
{
var response = this.Sence(id);
this.Connection.SendAsync("Send", connectionId, "ApiResult", response.ToJson());
});
//server call node update
this.Connection.On(nameof(INodeService.EditNode), (EditNodeModel model) =>
{
this.EditNode(model);
});
this.Connection.On(nameof(INodeService.DeleteNode), (Guid model) =>
{
this.DeleteNode(model);
});
this.Connection.On(nameof(INodeService.CreateSence), (EditSenceModel model) =>
{
this.CreateSence(model);
});
this.Connection.On(nameof(INodeService.EditSence), (EditSenceModel model) =>
{
this.EditSence(model);
});
this.Connection.On(nameof(INodeService.DeleteSence), (Guid model) =>
{
this.DeleteSence(model);
});
this.Connection.On(nameof(INodeService.EditDevice), (EditDeviceModel model) =>
{
this.EditDevice(model);
});
this.Connection.On(nameof(INodeService.DeleteDevice), (Guid model) =>
{
this.DeleteDevice(model);
});
this.Connection.On(nameof(INodeService.CreateCommand), (EditCommandModel model) =>
{
this.CreateCommand(model);
});
this.Connection.On(nameof(INodeService.EditCommand), (EditCommandModel model) =>
{
this.EditCommand(model);
});
this.Connection.On(nameof(INodeService.DeleteCommand), (Guid model) =>
{
this.DeleteCommand(model);
});
}
public void Dispose()
{
this._tokenSource.Cancel();
this.Close();
}
}
}