Improve MdnsDiscovery

This commit is contained in:
Stone_Red
2023-03-07 18:10:01 +01:00
parent 894a23855f
commit 2f906063e9
3 changed files with 121 additions and 104 deletions
@@ -47,8 +47,9 @@
@code { @code {
List<IPAddress> ipAddresses = new List<IPAddress>(); List<IPAddress> ipAddresses = new List<IPAddress>();
protected override async Task OnInitializedAsync() protected override void OnInitialized()
{ {
ipAddresses.AddRange(MdnsDiscovery.GetChachedDevices());
MdnsDiscovery.OnDeviceFound += address => MdnsDiscovery.OnDeviceFound += address =>
{ {
ipAddresses.Add(address); ipAddresses.Add(address);
@@ -10,138 +10,149 @@ namespace Elektrifikatsiya.Services.Implementations;
public class DeviceManagmentService : IDeviceManagmentService public class DeviceManagmentService : IDeviceManagmentService
{ {
private readonly DeviceManagmentDatabaseContext deviceManagmentDatabaseContext; private readonly DeviceManagmentDatabaseContext deviceManagmentDatabaseContext;
private readonly IServiceScopeFactory serviceScopeFactory; private readonly IServiceScopeFactory serviceScopeFactory;
private readonly IDeviceStatusService deviceStatusService; private readonly IDeviceStatusService deviceStatusService;
private readonly HttpClient httpClient; private readonly ILogger<DeviceManagmentService> logger;
private readonly HttpClient httpClient;
public DeviceManagmentService(IServiceScopeFactory serviceScopeFactory, IDeviceStatusService deviceStatusService, HttpClient httpClient) public DeviceManagmentService(IServiceScopeFactory serviceScopeFactory, IDeviceStatusService deviceStatusService, ILogger<DeviceManagmentService> logger, HttpClient httpClient)
{ {
this.serviceScopeFactory = serviceScopeFactory; this.serviceScopeFactory = serviceScopeFactory;
this.deviceStatusService = deviceStatusService; this.deviceStatusService = deviceStatusService;
this.httpClient = httpClient; this.logger = logger;
this.httpClient = httpClient;
} }
public Result<Device> GetDevice(string macAdress) public Result<Device> GetDevice(string macAdress)
{ {
Result<List<Device>> getDevicesResult = deviceStatusService.GetDevices(); Result<List<Device>> getDevicesResult = deviceStatusService.GetDevices();
if (getDevicesResult.IsFailed) if (getDevicesResult.IsFailed)
{ {
return getDevicesResult.ToResult(); return getDevicesResult.ToResult();
} }
Device? device = getDevicesResult.Value.FirstOrDefault(d => d.MacAddress == macAdress); Device? device = getDevicesResult.Value.FirstOrDefault(d => d.MacAddress == macAdress);
if (device is null) if (device is null)
{ {
return Result.Fail("Device does not exist!"); return Result.Fail("Device does not exist!");
} }
return device; return device;
} }
public Result<List<Device>> GetDevices() public Result<List<Device>> GetDevices()
{ {
Result<List<Device>> getDevicesResult = deviceStatusService.GetDevices(); Result<List<Device>> getDevicesResult = deviceStatusService.GetDevices();
if (getDevicesResult.IsFailed) if (getDevicesResult.IsFailed)
{ {
return getDevicesResult.ToResult(); return getDevicesResult.ToResult();
} }
return getDevicesResult.Value.ToList(); return getDevicesResult.Value.ToList();
} }
public Result<List<Device>> GetDevicesInRoom(string room) public Result<List<Device>> GetDevicesInRoom(string room)
{ {
Result<List<Device>> getDevicesResult = deviceStatusService.GetDevices(); Result<List<Device>> getDevicesResult = deviceStatusService.GetDevices();
if (getDevicesResult.IsFailed) if (getDevicesResult.IsFailed)
{ {
return getDevicesResult.ToResult(); return getDevicesResult.ToResult();
} }
return getDevicesResult.Value.Where(d => d.Room == room).ToList(); return getDevicesResult.Value.Where(d => d.Room == room).ToList();
} }
public Result<List<Device>> GetDevicesOfUser(int userId) public Result<List<Device>> GetDevicesOfUser(int userId)
{ {
Result<List<Device>> getDevicesResult = deviceStatusService.GetDevices(); Result<List<Device>> getDevicesResult = deviceStatusService.GetDevices();
if (getDevicesResult.IsFailed) if (getDevicesResult.IsFailed)
{ {
return getDevicesResult.ToResult(); return getDevicesResult.ToResult();
} }
return getDevicesResult.Value.Where(d => d.User.Id == userId).ToList(); return getDevicesResult.Value.Where(d => d.User.Id == userId).ToList();
} }
public async Task<Result<Device>> RegisterDevice(IPAddress ip, User user, string? name = null, string room = "default") public async Task<Result<Device>> RegisterDevice(IPAddress ip, User user, string? name = null, string room = "default")
{ {
using IServiceScope scope = serviceScopeFactory.CreateScope(); using IServiceScope scope = serviceScopeFactory.CreateScope();
DeviceManagmentDatabaseContext deviceManagmentDatabaseContext = scope.ServiceProvider.GetRequiredService<DeviceManagmentDatabaseContext>(); DeviceManagmentDatabaseContext deviceManagmentDatabaseContext = scope.ServiceProvider.GetRequiredService<DeviceManagmentDatabaseContext>();
ShellyResponse? shellyResponse = await httpClient.GetFromJsonAsync<ShellyResponse>($"http://{ip}/shelly"); ShellyResponse? shellyResponse = null;
if (shellyResponse is null || shellyResponse.Type != "SHPLG-S") try
{ {
return Result.Fail("Device is not reachable or not a \"SHPLG-S\"!"); shellyResponse = await httpClient.GetFromJsonAsync<ShellyResponse>($"http://{ip}/shelly");
} }
catch (Exception ex)
{
logger.LogError("HTTP request failed! {message}", ex.Message);
}
string mac = shellyResponse.Mac; if (shellyResponse is null || shellyResponse.Type != "SHPLG-S")
{
return Result.Fail("Device is not reachable or not a \"SHPLG-S\"!");
}
if (!PhysicalAddress.TryParse(mac, out _)) string mac = shellyResponse.Mac;
{
return Result.Fail("Invalid mac address!");
}
Device device = new Device(mac, name ?? mac, ip, user, room); if (!PhysicalAddress.TryParse(mac, out _))
{
return Result.Fail("Invalid mac address!");
}
deviceManagmentDatabaseContext.Add(device); Device device = new Device(mac, name ?? mac, ip, user, room);
Result saveDatabaseChangesResult = await Result.Try(Task () => deviceManagmentDatabaseContext.SaveChangesAsync());
Result trackDeviceResult = deviceStatusService.TrackDevice(device); _ = deviceManagmentDatabaseContext.Add(device);
Result saveDatabaseChangesResult = await Result.Try(Task () => deviceManagmentDatabaseContext.SaveChangesAsync());
return Result.Merge(saveDatabaseChangesResult, trackDeviceResult).ToResult(device); Result trackDeviceResult = deviceStatusService.TrackDevice(device);
}
public async Task<Result> UnregisterDevice(string macAdress) return Result.Merge(saveDatabaseChangesResult, trackDeviceResult).ToResult(device);
{ }
using IServiceScope scope = serviceScopeFactory.CreateScope();
DeviceManagmentDatabaseContext deviceManagmentDatabaseContext = scope.ServiceProvider.GetRequiredService<DeviceManagmentDatabaseContext>(); public async Task<Result> UnregisterDevice(string macAdress)
{
using IServiceScope scope = serviceScopeFactory.CreateScope();
DeviceManagmentDatabaseContext deviceManagmentDatabaseContext = scope.ServiceProvider.GetRequiredService<DeviceManagmentDatabaseContext>();
Result<Device> getDeviceResult = GetDevice(macAdress); Result<Device> getDeviceResult = GetDevice(macAdress);
if (getDeviceResult.IsFailed) if (getDeviceResult.IsFailed)
{ {
return getDeviceResult.ToResult(); return getDeviceResult.ToResult();
} }
Result untrackDeviceResult = deviceStatusService.UntrackDevice(macAdress); Result untrackDeviceResult = deviceStatusService.UntrackDevice(macAdress);
if (untrackDeviceResult.IsFailed) if (untrackDeviceResult.IsFailed)
{ {
return untrackDeviceResult; return untrackDeviceResult;
} }
deviceManagmentDatabaseContext.Remove(getDeviceResult.Value); _ = deviceManagmentDatabaseContext.Remove(getDeviceResult.Value);
return await Result.Try(Task () => deviceManagmentDatabaseContext.SaveChangesAsync()); return await Result.Try(Task () => deviceManagmentDatabaseContext.SaveChangesAsync());
} }
public async Task<Result> UpdateDevice(Device device) public async Task<Result> UpdateDevice(Device device)
{ {
Result result = deviceStatusService.UpdateDeviceStatus(device); Result result = deviceStatusService.UpdateDeviceStatus(device);
if (result.IsFailed) if (result.IsFailed)
{ {
return result; return result;
} }
deviceManagmentDatabaseContext.Update(device); _ = deviceManagmentDatabaseContext.Update(device);
return await Result.Try(Task () => deviceManagmentDatabaseContext.SaveChangesAsync()); return await Result.Try(Task () => deviceManagmentDatabaseContext.SaveChangesAsync());
} }
} }
@@ -1,20 +1,25 @@
using System.Net; using System.Net;
using FluentResults;
using Tmds.MDns; using Tmds.MDns;
namespace Elektrifikatsiya.Utilities; namespace Elektrifikatsiya.Utilities;
public static class MdnsDiscovery public static class MdnsDiscovery
{ {
public static event Action<IPAddress> OnDeviceFound; public static event Action<IPAddress> OnDeviceFound = null!;
static ServiceBrowser serviceBrowser = new ServiceBrowser(); private static readonly ServiceBrowser serviceBrowser = new ServiceBrowser();
static MdnsDiscovery() static MdnsDiscovery()
{ {
serviceBrowser.StartBrowse("_http._tcp"); serviceBrowser.StartBrowse("_http._tcp");
serviceBrowser.ServiceAdded += (_, eventArgs) => OnDeviceFound?.Invoke(eventArgs.Announcement.Addresses.First()); serviceBrowser.ServiceAdded += (_, eventArgs) => OnDeviceFound?.Invoke(eventArgs.Announcement.Addresses.First());
serviceBrowser.ServiceChanged += (_, eventArgs) => OnDeviceFound?.Invoke(eventArgs.Announcement.Addresses.First()); serviceBrowser.ServiceChanged += (_, eventArgs) => OnDeviceFound?.Invoke(eventArgs.Announcement.Addresses.First());
serviceBrowser.ServiceRemoved += (_, eventArgs) => OnDeviceFound?.Invoke(eventArgs.Announcement.Addresses.First()); serviceBrowser.ServiceRemoved += (_, eventArgs) => OnDeviceFound?.Invoke(eventArgs.Announcement.Addresses.First());
} }
public static IEnumerable<IPAddress> GetChachedDevices()
{
return serviceBrowser.Services.Select(s => s.Addresses.First());
}
} }