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; }
///
/// Sets or returns the type of notification, being either a uuid, device type, service type or upnp:rootdevice.
///
public string NotificationType => _device.NotificationType;
///
/// Sets or returns the universal service name (USN) of the device.
///
public string Usn => _device.Usn;
///
/// Sets or returns a URL pointing to the device description document for this device.
///
public Uri DescriptionLocation => _device.DescriptionLocation;
///
/// Sets or returns the length of time this information is valid for (from the time).
///
public TimeSpan CacheLifetime => _device.CacheLifetime;
///
/// Sets or returns the date and time this information was received.
///
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();
}
}