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.
674 lines
25 KiB
674 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(Helper.Instance.GetLocalIP(), 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");
|
|
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();
|
|
}
|
|
}
|
|
} |