159 lines
4.5 KiB
C#
159 lines
4.5 KiB
C#
using System.Collections.Specialized;
|
|
|
|
namespace SddpViewer;
|
|
|
|
using System.Collections.ObjectModel;
|
|
using System.Threading.Tasks;
|
|
using Avalonia.Threading;
|
|
using CommunityToolkit.Mvvm.ComponentModel;
|
|
using CommunityToolkit.Mvvm.Input;
|
|
using Rssdp;
|
|
|
|
public sealed partial class MainWindowViewModel : ObservableObject, IDisposable
|
|
{
|
|
public MainWindowViewModel()
|
|
{
|
|
NetworkAdapters = NetworkAdapter.GetAvailableNetworkAdapter().ToArray();
|
|
SelectedNetworkAdapter = NetworkAdapters.FirstOrDefault(x => x.IpAddress.ToString() == DeviceIpAddress);
|
|
SddpDevices = [];
|
|
SddpDevices.CollectionChanged += SddpDevices_OnCollectionChanged;
|
|
}
|
|
|
|
private static async void SddpDevices_OnCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
|
|
{
|
|
switch (e.Action)
|
|
{
|
|
case NotifyCollectionChangedAction.Add:
|
|
await AddAction(e.NewItems);
|
|
break;
|
|
case NotifyCollectionChangedAction.Remove:
|
|
RemoveAction(e.OldItems);
|
|
break;
|
|
case NotifyCollectionChangedAction.Replace:
|
|
RemoveAction(e.OldItems);
|
|
await AddAction(e.NewItems);
|
|
break;
|
|
case NotifyCollectionChangedAction.Reset:
|
|
RemoveAction(sender as ObservableCollection<DiscoveredDeviceViewModel>);
|
|
break;
|
|
case NotifyCollectionChangedAction.Move:
|
|
break;
|
|
default:
|
|
throw new ArgumentOutOfRangeException();
|
|
}
|
|
}
|
|
|
|
private static void RemoveAction(IList? list)
|
|
{
|
|
foreach (object eOldItem in list ?? Array.Empty<object>())
|
|
{
|
|
if (eOldItem is DiscoveredDeviceViewModel discoveredDeviceViewModel)
|
|
{
|
|
discoveredDeviceViewModel.Dispose();
|
|
}
|
|
}
|
|
}
|
|
|
|
private static async Task AddAction(IList? list)
|
|
{
|
|
foreach (object eNewItem in list ?? Array.Empty<object>())
|
|
{
|
|
if (eNewItem is DiscoveredDeviceViewModel discoveredDeviceViewModel)
|
|
{
|
|
await discoveredDeviceViewModel.GetFurtherInformationAsync();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void LocatorOnDeviceUnavailable(object? sender, DeviceUnavailableEventArgs e)
|
|
{
|
|
var existingDevice = SddpDevices.FirstOrDefault(x => string.Equals(x.Usn, e.DiscoveredDevice.Usn, StringComparison.Ordinal));
|
|
if (existingDevice is null)
|
|
return;
|
|
Dispatcher.UIThread.Invoke(() => SddpDevices.Remove(existingDevice));
|
|
}
|
|
|
|
private void LocatorOnDeviceAvailable(object? sender, DeviceAvailableEventArgs e)
|
|
{
|
|
if (!e.IsNewlyDiscovered)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var discoveredDeviceViewModel = new DiscoveredDeviceViewModel(e.DiscoveredDevice);
|
|
if (!SddpDevices.Contains(discoveredDeviceViewModel))
|
|
Dispatcher.UIThread.Invoke(() => SddpDevices.Add(discoveredDeviceViewModel));
|
|
}
|
|
|
|
[ObservableProperty]
|
|
public partial IReadOnlyList<NetworkAdapter> NetworkAdapters { get; set; }
|
|
|
|
[ObservableProperty]
|
|
public partial NetworkAdapter? SelectedNetworkAdapter { get; set; }
|
|
|
|
[ObservableProperty]
|
|
public partial string DeviceIpAddress { get; set; } = "192.168.42.192";
|
|
|
|
[ObservableProperty]
|
|
public partial string NotificationFilter { get; set; } = "upnp:rootdevice";
|
|
|
|
private SsdpDeviceLocator? _locator;
|
|
|
|
public ObservableCollection<DiscoveredDeviceViewModel> SddpDevices { get; }
|
|
|
|
[RelayCommand]
|
|
private async Task SearchDevicesNowAsync()
|
|
{
|
|
SddpDevices.Clear();
|
|
if (_locator is not null)
|
|
{
|
|
_locator.StopListeningForNotifications();
|
|
_locator.DeviceAvailable -= LocatorOnDeviceAvailable;
|
|
_locator.DeviceUnavailable -= LocatorOnDeviceUnavailable;
|
|
_locator.Dispose();
|
|
}
|
|
|
|
await StartListening(async locator =>
|
|
{
|
|
foreach (var discoveredSsdpDevice in await locator.SearchAsync())
|
|
{
|
|
var discoveredDeviceViewModel = new DiscoveredDeviceViewModel(discoveredSsdpDevice);
|
|
Dispatcher.UIThread.Invoke(() => SddpDevices.Add(discoveredDeviceViewModel));
|
|
}
|
|
});
|
|
}
|
|
|
|
[RelayCommand]
|
|
private async Task ResearchAsync()
|
|
{
|
|
if (_locator is not null)
|
|
{
|
|
await _locator.SearchAsync();
|
|
}
|
|
}
|
|
|
|
[RelayCommand]
|
|
private async Task StartListening(Func<SsdpDeviceLocator, Task>? action = null)
|
|
{
|
|
_locator = new SsdpDeviceLocator(SelectedNetworkAdapter?.IpAddress.ToString());
|
|
if (!string.IsNullOrWhiteSpace(NotificationFilter))
|
|
{
|
|
_locator.NotificationFilter = NotificationFilter;
|
|
}
|
|
|
|
if (action is not null)
|
|
{
|
|
await action.Invoke(_locator);
|
|
}
|
|
|
|
_locator.DeviceAvailable += LocatorOnDeviceAvailable;
|
|
_locator.DeviceUnavailable += LocatorOnDeviceUnavailable;
|
|
_locator.StartListeningForNotifications();
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
_locator?.Dispose();
|
|
}
|
|
}
|