Add Windows desktop version

This commit is contained in:
renato97
2025-12-17 19:20:55 +00:00
parent 93dbe0941e
commit 8921d7f2a6
36 changed files with 2760 additions and 0 deletions

View File

@@ -0,0 +1,169 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.NetworkInformation;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Threading;
using System.Threading.Tasks;
namespace StreamPlayer.Desktop.Services;
public sealed class WindowsDnsService
{
private static readonly string[] PreferredDns = { "8.8.8.8", "8.8.4.4" };
private bool _attempted;
public async Task<DnsSetupResult> EnsureGoogleDnsAsync(CancellationToken cancellationToken)
{
if (!OperatingSystem.IsWindows())
{
return DnsSetupResult.CreateSuccess();
}
if (_attempted)
{
return DnsSetupResult.CreateSuccess();
}
_attempted = true;
bool needsElevation = !IsRunningAsAdministrator();
if (needsElevation)
{
var consent = PromptForElevation();
if (!consent)
{
return DnsSetupResult.CreateFailure("Se canceló la solicitud de permisos. Ejecuta la app como administrador o configura los DNS manualmente (8.8.8.8 y 8.8.4.4).");
}
}
var interfaces = GetEligibleInterfaces().ToList();
if (interfaces.Count == 0)
{
return DnsSetupResult.CreateSuccess("No se detectaron adaptadores de red activos para forzar DNS.");
}
foreach (var adapter in interfaces)
{
bool primary = await RunNetshAsync(
$"interface ipv4 set dns name=\"{adapter}\" static {PreferredDns[0]} primary",
cancellationToken,
needsElevation);
bool secondary = await RunNetshAsync(
$"interface ipv4 add dns name=\"{adapter}\" {PreferredDns[1]} index=2",
cancellationToken,
needsElevation);
if (!primary || !secondary)
{
return DnsSetupResult.CreateFailure($"No se pudo configurar DNS para el adaptador \"{adapter}\". Verifica permisos de administrador o configura manualmente los DNS de Google.");
}
}
return DnsSetupResult.CreateSuccess("DNS de Google aplicados correctamente a los adaptadores de red activos.");
}
private static bool IsRunningAsAdministrator()
{
if (!OperatingSystem.IsWindows())
{
return false;
}
try
{
using var identity = WindowsIdentity.GetCurrent();
var principal = new WindowsPrincipal(identity);
return principal.IsInRole(WindowsBuiltInRole.Administrator);
}
catch
{
return false;
}
}
private static IEnumerable<string> GetEligibleInterfaces()
{
return NetworkInterface.GetAllNetworkInterfaces()
.Where(ni =>
ni.OperationalStatus == OperationalStatus.Up &&
ni.NetworkInterfaceType != NetworkInterfaceType.Loopback &&
ni.NetworkInterfaceType != NetworkInterfaceType.Tunnel &&
ni.Supports(NetworkInterfaceComponent.IPv4))
.Select(ni => ni.Name);
}
private static bool PromptForElevation()
{
try
{
var psi = new ProcessStartInfo
{
FileName = "netsh",
Arguments = "advfirewall show currentprofile",
UseShellExecute = true,
Verb = "runas",
CreateNoWindow = true
};
using var process = Process.Start(psi);
if (process == null)
{
return false;
}
process.WaitForExit();
return process.ExitCode == 0;
}
catch (System.ComponentModel.Win32Exception ex) when (ex.NativeErrorCode == 1223)
{
// User cancelled UAC prompt.
return false;
}
catch
{
return false;
}
}
private static async Task<bool> RunNetshAsync(string arguments, CancellationToken cancellationToken, bool elevate)
{
try
{
var psi = new ProcessStartInfo
{
FileName = "netsh",
Arguments = arguments,
UseShellExecute = elevate,
RedirectStandardOutput = !elevate,
RedirectStandardError = !elevate,
CreateNoWindow = true
};
if (elevate)
{
psi.Verb = "runas";
}
using var process = Process.Start(psi);
if (process == null)
{
return false;
}
await process.WaitForExitAsync(cancellationToken);
return process.ExitCode == 0;
}
catch (System.ComponentModel.Win32Exception ex) when (ex.NativeErrorCode == 1223)
{
return false;
}
catch
{
return false;
}
}
}
public sealed record DnsSetupResult(bool Success, string Message)
{
public static DnsSetupResult CreateSuccess(string message = "") => new(true, message);
public static DnsSetupResult CreateFailure(string message) => new(false, message);
}