150 lines
4.3 KiB
C#
150 lines
4.3 KiB
C#
using System.Net;
|
|
using System.Net.NetworkInformation;
|
|
|
|
namespace SddpViewer;
|
|
|
|
using System;
|
|
using System.Threading.Tasks;
|
|
using CommunityToolkit.Mvvm.ComponentModel;
|
|
using Rssdp;
|
|
|
|
public partial class DiscoveredDeviceViewModel : ObservableObject, IDisposable
|
|
{
|
|
private readonly DiscoveredSsdpDevice _device;
|
|
private SsdpDevice? _ssdpDevice;
|
|
private readonly CancellationTokenSource _cancellationTokenSource = new();
|
|
|
|
public DiscoveredDeviceViewModel(DiscoveredSsdpDevice device)
|
|
{
|
|
_device = device;
|
|
ResponseHeader = GetResponseHeader();
|
|
DiscoveredAt = DateTime.Now;
|
|
IpAddress = EvaluateIpAddress(device);
|
|
MacAddress = EvaluateMacAddress();
|
|
HostName = EvaluateHostName();
|
|
RunPing(_cancellationTokenSource.Token);
|
|
}
|
|
|
|
private async void RunPing(CancellationToken token)
|
|
{
|
|
try
|
|
{
|
|
using Ping ping = new();
|
|
while (!token.IsCancellationRequested)
|
|
{
|
|
var result = await ping.SendPingAsync(IpAddress, TimeSpan.FromSeconds(1), cancellationToken: token).ConfigureAwait(true);
|
|
Online = result.Status == IPStatus.Success;
|
|
await Task.Delay(1000, token).ConfigureAwait(true);
|
|
}
|
|
}
|
|
catch (TaskCanceledException e)
|
|
{
|
|
Console.WriteLine(e);
|
|
}
|
|
catch (OperationCanceledException e)
|
|
{
|
|
Console.WriteLine(e);
|
|
}
|
|
}
|
|
|
|
public string HostName { get; set; }
|
|
|
|
public string MacAddress { get; set; }
|
|
|
|
public IPAddress IpAddress { get; set; }
|
|
|
|
public DateTime DiscoveredAt { get; }
|
|
|
|
[ObservableProperty]
|
|
public partial string ResponseHeader { get; set; }
|
|
|
|
[ObservableProperty]
|
|
public partial bool Online { get; set; }
|
|
|
|
/// <summary>
|
|
/// Sets or returns the type of notification, being either a uuid, device type, service type or upnp:rootdevice.
|
|
/// </summary>
|
|
public string NotificationType => _device.NotificationType;
|
|
|
|
/// <summary>
|
|
/// Sets or returns the universal service name (USN) of the device.
|
|
/// </summary>
|
|
public string Usn => _device.Usn;
|
|
|
|
/// <summary>
|
|
/// Sets or returns a URL pointing to the device description document for this device.
|
|
/// </summary>
|
|
public Uri DescriptionLocation => _device.DescriptionLocation;
|
|
|
|
/// <summary>
|
|
/// Sets or returns the length of time this information is valid for (from the <see cref="P:Rssdp.DiscoveredSsdpDevice.AsAt" /> time).
|
|
/// </summary>
|
|
public TimeSpan CacheLifetime => _device.CacheLifetime;
|
|
|
|
/// <summary>
|
|
/// Sets or returns the date and time this information was received.
|
|
/// </summary>
|
|
public DateTimeOffset AsAt => _device.AsAt;
|
|
|
|
[ObservableProperty]
|
|
public partial string FriendlyName { get; set; } = "";
|
|
|
|
[ObservableProperty]
|
|
public partial SsdpDeviceIcon? Icon { get; set; }
|
|
|
|
[ObservableProperty]
|
|
public partial Uri? PresentationUrl { get; set; }
|
|
|
|
[ObservableProperty]
|
|
public partial string ModelNumber { get; set; } = "";
|
|
|
|
[ObservableProperty]
|
|
public partial string Version { get; set; } = "";
|
|
|
|
public void Cancel()
|
|
{
|
|
_cancellationTokenSource.Cancel();
|
|
}
|
|
|
|
public async Task GetFurtherInformationAsync()
|
|
{
|
|
_ssdpDevice = await _device.GetDeviceInfo().ConfigureAwait(false);
|
|
FriendlyName = _ssdpDevice.FriendlyName;
|
|
Icon = _ssdpDevice.Icons.MinBy(x => x.Height);
|
|
PresentationUrl = _ssdpDevice.PresentationUrl;
|
|
ModelNumber = _ssdpDevice.ModelNumber;
|
|
Version = _ssdpDevice.SerialNumber?.Split(',').Last() ?? new Version().ToString();
|
|
}
|
|
|
|
private string EvaluateHostName() => Dns.GetHostEntry(IpAddress).HostName;
|
|
|
|
private string GetResponseHeader()
|
|
{
|
|
return _device.ResponseHeaders is null
|
|
? ""
|
|
: string.Join("," + Environment.NewLine, _device.ResponseHeaders.Select(x => $"{{{x.Key} : {string.Join(";", x.Value)}}}"));
|
|
}
|
|
|
|
private IPAddress EvaluateIpAddress(DiscoveredSsdpDevice device) =>
|
|
IPAddress.TryParse(device.DescriptionLocation.Host, out var value) ? value : IPAddress.Any;
|
|
|
|
private string EvaluateMacAddress()
|
|
{
|
|
if (!ArpLookup.Arp.IsSupported)
|
|
return "not supported";
|
|
var lookupResult = ArpLookup.Arp.Lookup(IpAddress);
|
|
return lookupResult is null ? "Unknown" : string.Join(":", lookupResult.GetAddressBytes().Select(b => $"{b:x2}"));
|
|
}
|
|
|
|
public override bool Equals(object? obj)
|
|
{
|
|
return obj is DiscoveredDeviceViewModel viewModel && Equals(viewModel.Usn, Usn);
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
_cancellationTokenSource.Cancel();
|
|
_cancellationTokenSource.Dispose();
|
|
}
|
|
}
|