diff --git a/ControlApp/App.xaml.cs b/ControlApp/App.xaml.cs index 5fd51db4..a6c30ba2 100644 --- a/ControlApp/App.xaml.cs +++ b/ControlApp/App.xaml.cs @@ -7,6 +7,7 @@ using Nefarius.DsHidMini.ControlApp.Models; using Nefarius.DsHidMini.ControlApp.Models.DshmConfigManager; +using Nefarius.DsHidMini.ControlApp.Models.Util.Web; using Nefarius.DsHidMini.ControlApp.Services; using Nefarius.DsHidMini.ControlApp.ViewModels.Pages; using Nefarius.DsHidMini.ControlApp.ViewModels.Windows; @@ -60,6 +61,8 @@ public partial class App services.AddSingleton(); services.AddSingleton
(); + services.AddSingleton(); + Log.Logger = new LoggerConfiguration() #if DEBUG .MinimumLevel.Debug() @@ -76,6 +79,12 @@ public partial class App client.BaseAddress = new Uri("https://buildbot.nefarius.at/"); client.DefaultRequestHeaders.UserAgent.ParseAdd(context.HostingEnvironment.ApplicationName); }); + + services.AddHttpClient("Docs", client => + { + client.BaseAddress = new Uri("https://docs.nefarius.at/"); + client.DefaultRequestHeaders.UserAgent.ParseAdd(context.HostingEnvironment.ApplicationName); + }); }).Build(); /// diff --git a/ControlApp/Models/Util/Web/Validator.cs b/ControlApp/Models/Util/Web/AddressValidator.cs similarity index 61% rename from ControlApp/Models/Util/Web/Validator.cs rename to ControlApp/Models/Util/Web/AddressValidator.cs index 11cfbec5..211967ba 100644 --- a/ControlApp/Models/Util/Web/Validator.cs +++ b/ControlApp/Models/Util/Web/AddressValidator.cs @@ -1,8 +1,7 @@ -using System.Net; +using System.Net.Http; +using System.Net.Http.Json; using System.Net.NetworkInformation; -using Newtonsoft.Json; - namespace Nefarius.DsHidMini.ControlApp.Models.Util.Web; [SuppressMessage("ReSharper", "InconsistentNaming")] @@ -54,21 +53,27 @@ public override int GetHashCode() } } -public class Validator +/// +/// Genuine controller MAC address validator. +/// +/// https://github.com/nefarius/DsHidMini/discussions/166 +public sealed class AddressValidator(IHttpClientFactory clientFactory) { - public static Uri ApiUrl => new("https://docs.nefarius.at/projects/DsHidMini/genuine_oui_db.json"); - - [Obsolete("Redesign to use modern HttpClient instead.")] - public static bool IsGenuineAddress(PhysicalAddress address) + public async Task IsGenuineAddress(PhysicalAddress address) { - using (WebClient client = new()) - { - IEnumerable ouiList = JsonConvert.DeserializeObject>(client.DownloadString(ApiUrl)) - .Select(e => new OUIEntry(e)); + using HttpClient client = clientFactory.CreateClient("Docs"); - OUIEntry device = new(address); + IEnumerable? ouiList = + (await client.GetFromJsonAsync>("/projects/DsHidMini/genuine_oui_db.json")) + ?.Select(e => new OUIEntry(e)); - return ouiList.Contains(device); + if (ouiList is null) + { + return false; } + + OUIEntry device = new(address); + + return ouiList.Contains(device); } } \ No newline at end of file diff --git a/ControlApp/ViewModels/Pages/DevicesViewModel.cs b/ControlApp/ViewModels/Pages/DevicesViewModel.cs index 2f7e4e32..f4fc84cd 100644 --- a/ControlApp/ViewModels/Pages/DevicesViewModel.cs +++ b/ControlApp/ViewModels/Pages/DevicesViewModel.cs @@ -2,6 +2,7 @@ using Nefarius.DsHidMini.ControlApp.Models; using Nefarius.DsHidMini.ControlApp.Models.DshmConfigManager; +using Nefarius.DsHidMini.ControlApp.Models.Util.Web; using Nefarius.DsHidMini.ControlApp.Services; using Nefarius.DsHidMini.ControlApp.ViewModels.UserControls; using Nefarius.Utilities.DeviceManagement.PnP; @@ -19,6 +20,7 @@ public partial class DevicesViewModel : ObservableObject, INavigationAware { private readonly AppSnackbarMessagesService _appSnackbarMessagesService; private readonly IContentDialogService _contentDialogService; + private readonly AddressValidator _addressValidator; private readonly DshmConfigManager _dshmConfigManager; private readonly DshmDevMan _dshmDevMan; @@ -36,8 +38,13 @@ public partial class DevicesViewModel : ObservableObject, INavigationAware [ObservableProperty] private DeviceViewModel? _selectedDevice; - public DevicesViewModel(DshmDevMan dshmDevMan, DshmConfigManager dshmConfigManager, - AppSnackbarMessagesService appSnackbarMessagesService, IContentDialogService contentDialogService) + public DevicesViewModel( + DshmDevMan dshmDevMan, + DshmConfigManager dshmConfigManager, + AppSnackbarMessagesService appSnackbarMessagesService, + IContentDialogService contentDialogService, + AddressValidator addressValidator + ) { _dshmDevMan = dshmDevMan; _dshmConfigManager = dshmConfigManager; @@ -45,6 +52,7 @@ public DevicesViewModel(DshmDevMan dshmDevMan, DshmConfigManager dshmConfigManag _dshmDevMan.ConnectedDeviceListUpdated += OnConnectedDevicesListUpdated; _dshmConfigManager.DshmConfigurationUpdated += OnDshmConfigUpdated; _contentDialogService = contentDialogService; + _addressValidator = addressValidator; RefreshDevicesList(); } @@ -59,16 +67,14 @@ public DevicesViewModel(DshmDevMan dshmDevMan, DshmConfigManager dshmConfigManag /// public bool HasDeviceSelected => SelectedDevice != null; - public Task OnNavigatedToAsync() + public async Task OnNavigatedToAsync() { Log.Logger.Debug( "Navigating to Devices page. Refreshing dynamic properties of each connected Device ViewModel."); foreach (DeviceViewModel device in Devices) { - device.RefreshDeviceSettings(); + await device.RefreshDeviceSettings(); } - - return Task.CompletedTask; } public Task OnNavigatedFromAsync() @@ -173,13 +179,27 @@ Reconnect the pending devices to make this change effective. private void RefreshDevicesList() { - App.Current.Dispatcher.BeginInvoke(new Action(() => + Application.Current.Dispatcher.BeginInvoke(new Action(async void () => { - Devices.Clear(); - foreach (PnPDevice device in _dshmDevMan.Devices) + try + { + Devices.Clear(); + foreach (DeviceViewModel newDev in _dshmDevMan.Devices.Select(device => new DeviceViewModel( + device, + _dshmDevMan, + _dshmConfigManager, + _appSnackbarMessagesService, + _contentDialogService, + _addressValidator + ))) + { + Devices.Add(newDev); + await newDev.RefreshDeviceSettings(); + } + } + catch (Exception e) { - Devices.Add(new DeviceViewModel(device, _dshmDevMan, _dshmConfigManager, _appSnackbarMessagesService, - _contentDialogService)); + Log.Logger.Error(e, "Error refreshing devices list"); } })); } diff --git a/ControlApp/ViewModels/UserControls/DeviceViewModel.cs b/ControlApp/ViewModels/UserControls/DeviceViewModel.cs index 3e2b7493..9cf8a675 100644 --- a/ControlApp/ViewModels/UserControls/DeviceViewModel.cs +++ b/ControlApp/ViewModels/UserControls/DeviceViewModel.cs @@ -1,9 +1,11 @@ -using System.Text.RegularExpressions; +using System.Net.NetworkInformation; +using System.Text.RegularExpressions; using Nefarius.DsHidMini.ControlApp.Models; using Nefarius.DsHidMini.ControlApp.Models.DshmConfigManager; using Nefarius.DsHidMini.ControlApp.Models.DshmConfigManager.Enums; using Nefarius.DsHidMini.ControlApp.Models.Enums; +using Nefarius.DsHidMini.ControlApp.Models.Util.Web; using Nefarius.DsHidMini.ControlApp.Services; using Nefarius.DsHidMini.IPC.Models.Drivers; using Nefarius.Utilities.DeviceManagement.PnP; @@ -19,6 +21,7 @@ public partial class DeviceViewModel : ObservableObject private readonly AppSnackbarMessagesService _appSnackbarMessagesService; private readonly Timer _batteryQuery; private readonly IContentDialogService _contentDialogService; + private readonly AddressValidator _addressValidator; private readonly DeviceData _deviceUserData; @@ -77,6 +80,12 @@ public partial class DeviceViewModel : ObservableObject /// private BluetoothPairingMode? _pairingMode; + /// + /// Whether the controller is deemed official Sony genuine by using the online address database. + /// + [ObservableProperty] + private bool _isGenuine; + // ------------------------------------------------------ METHODS @@ -86,22 +95,28 @@ public partial class DeviceViewModel : ObservableObject // ------------------------------------------------------ CONSTRUCTOR - internal DeviceViewModel(PnPDevice device, DshmDevMan dshmDevMan, DshmConfigManager dshmConfigManager, - AppSnackbarMessagesService appSnackbarMessagesService, IContentDialogService contentDialogService) + internal DeviceViewModel( + PnPDevice device, + DshmDevMan dshmDevMan, + DshmConfigManager dshmConfigManager, + AppSnackbarMessagesService appSnackbarMessagesService, + IContentDialogService contentDialogService, + AddressValidator addressValidator + ) { Device = device; - Log.Logger.Debug($"Creating Device ViewModel for device '{DeviceAddress}'"); + Log.Logger.Debug("Creating Device ViewModel for device '{S}'", DeviceAddress); _dshmDevMan = dshmDevMan; _dshmConfigManager = dshmConfigManager; _appSnackbarMessagesService = appSnackbarMessagesService; _contentDialogService = contentDialogService; + _addressValidator = addressValidator; _batteryQuery = new Timer(UpdateBatteryStatus, null, 10000, 10000); _deviceUserData = _dshmConfigManager.GetDeviceData(DeviceAddress); // Loads correspondent controller data based on controller's MAC address //DisplayName = DeviceAddress; - RefreshDeviceSettings(); } public PnPDevice Device { get; } @@ -123,7 +138,7 @@ internal DeviceViewModel(PnPDevice device, DshmDevMan dshmDevMan, DshmConfigMana /// /// State of Device's current HID Mode in relation to mode it's expected to be /// - public bool IsHidModeMismatched => HidEmulationMode != ExpectedHidMode ? true : false; + public bool IsHidModeMismatched => HidEmulationMode != ExpectedHidMode; /// /// Summary of device's current HID mode and Settings mode @@ -249,12 +264,12 @@ public string? CustomPairingAddress /// /// Index of the desired Bluetooth pairing mode /// - public int PairingMode + public BluetoothPairingMode PairingMode { - get => (int)_pairingMode; + get => _pairingMode ?? BluetoothPairingMode.Auto; set { - _pairingMode = (BluetoothPairingMode)value; + _pairingMode = value; OnPropertyChanged(); } } @@ -384,11 +399,11 @@ private void AdjustSettingsTabState() } [RelayCommand] - public void RefreshDeviceSettings() + public async Task RefreshDeviceSettings() { Log.Logger.Debug("Refreshing ViewModel of Device '{Address}'", DeviceAddress); // Bluetooth - PairingMode = (int)_deviceUserData.BluetoothPairingMode; + PairingMode = _deviceUserData.BluetoothPairingMode; CustomPairingAddress = _deviceUserData.PairingAddress; // Settings and selected profile @@ -398,22 +413,24 @@ public void RefreshDeviceSettings() Log.Logger.Information( "Device '{S}' set for {SettingsContext} HID Mode (currently in {HidModeShort1}), {BluetoothPairingMode} Bluetooth pairing mode." - , DeviceAddress, ExpectedHidMode, HidModeShort, (BluetoothPairingMode)PairingMode); - if ((BluetoothPairingMode)PairingMode == BluetoothPairingMode.Custom) + , DeviceAddress, ExpectedHidMode, HidModeShort, PairingMode); + if (PairingMode == BluetoothPairingMode.Custom) { Log.Logger.Information("Custom pairing address: {CustomPairingAddress}.", CustomPairingAddress); } + IsGenuine = await _addressValidator.IsGenuineAddress(PhysicalAddress.Parse(DeviceAddress)); + AdjustSettingsTabState(); OnPropertyChanged(nameof(DeviceSettingsStatus)); OnPropertyChanged(nameof(IsHidModeMismatched)); } [RelayCommand] - private void ApplyChanges() + private async Task ApplyChanges() { Log.Logger.Information("Saving and applying changes made to Device '{DeviceAddress}'", DeviceAddress); - _deviceUserData.BluetoothPairingMode = (BluetoothPairingMode)PairingMode; + _deviceUserData.BluetoothPairingMode = PairingMode; string formattedCustomMacAddress = Regex.Replace(CustomPairingAddress, @"[^a-fA-F0-9]", "").ToUpper(); if (formattedCustomMacAddress.Length > 12) @@ -436,7 +453,7 @@ private void ApplyChanges() _dshmConfigManager.SaveChangesAndUpdateDsHidMiniConfigFile(); _appSnackbarMessagesService.ShowDsHidMiniConfigurationUpdateSuccessMessage(); - RefreshDeviceSettings(); + await RefreshDeviceSettings(); } [RelayCommand]