release
This commit is contained in:
@ -1,5 +1,6 @@
|
|||||||
<Application xmlns="https://github.com/avaloniaui"
|
<Application xmlns="https://github.com/avaloniaui"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:dialogHostAvalonia="clr-namespace:DialogHostAvalonia;assembly=DialogHost.Avalonia"
|
||||||
x:Class="MicrosocksGUI.App"
|
x:Class="MicrosocksGUI.App"
|
||||||
xmlns:local="using:MicrosocksGUI"
|
xmlns:local="using:MicrosocksGUI"
|
||||||
RequestedThemeVariant="Default">
|
RequestedThemeVariant="Default">
|
||||||
@ -11,5 +12,6 @@
|
|||||||
|
|
||||||
<Application.Styles>
|
<Application.Styles>
|
||||||
<FluentTheme />
|
<FluentTheme />
|
||||||
|
<dialogHostAvalonia:DialogHostStyles />
|
||||||
</Application.Styles>
|
</Application.Styles>
|
||||||
</Application>
|
</Application>
|
||||||
@ -22,6 +22,7 @@
|
|||||||
<IncludeAssets Condition="'$(Configuration)' != 'Debug'">None</IncludeAssets>
|
<IncludeAssets Condition="'$(Configuration)' != 'Debug'">None</IncludeAssets>
|
||||||
<PrivateAssets Condition="'$(Configuration)' != 'Debug'">All</PrivateAssets>
|
<PrivateAssets Condition="'$(Configuration)' != 'Debug'">All</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
<PackageReference Include="DialogHost.Avalonia" Version="0.10.0" />
|
||||||
<PackageReference Include="ReactiveUI.Avalonia" Version="11.3.8"/>
|
<PackageReference Include="ReactiveUI.Avalonia" Version="11.3.8"/>
|
||||||
<PackageReference Include="ReactiveUI.SourceGenerators" Version="2.5.1">
|
<PackageReference Include="ReactiveUI.SourceGenerators" Version="2.5.1">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
|||||||
24
MicrosocksGUI/Services/IServiceManager.cs
Normal file
24
MicrosocksGUI/Services/IServiceManager.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
namespace MicrosocksGUI.Services;
|
||||||
|
|
||||||
|
public interface IServiceManager
|
||||||
|
{
|
||||||
|
public record Arguments(string Ip, string Port);
|
||||||
|
|
||||||
|
public void CreateIfNotExists();
|
||||||
|
|
||||||
|
public void Start();
|
||||||
|
|
||||||
|
public void Stop();
|
||||||
|
|
||||||
|
public void Restart();
|
||||||
|
|
||||||
|
public bool IsRunning();
|
||||||
|
|
||||||
|
public bool GetAutostart();
|
||||||
|
|
||||||
|
public void SetAutostart(bool autostart);
|
||||||
|
|
||||||
|
public Arguments GetArguments();
|
||||||
|
|
||||||
|
public void SetArguments(Arguments arguments);
|
||||||
|
}
|
||||||
130
MicrosocksGUI/Services/WindowsServiceManager.cs
Normal file
130
MicrosocksGUI/Services/WindowsServiceManager.cs
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.ServiceProcess;
|
||||||
|
|
||||||
|
namespace MicrosocksGUI.Services;
|
||||||
|
|
||||||
|
public class WindowsServiceManager : IServiceManager
|
||||||
|
{
|
||||||
|
private record NssmResult(string Output, string Errors);
|
||||||
|
private readonly ServiceController _serviceController = new("MicroSocks");
|
||||||
|
|
||||||
|
public void CreateIfNotExists()
|
||||||
|
{
|
||||||
|
if (!RunNssmProcess("status MicroSocks").Errors.Contains("Can't open service!"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var result = RunNssmProcess("install MicroSocks microsocks.exe -i 127.0.0.1 -p 1080");
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(result.Errors))
|
||||||
|
{
|
||||||
|
throw new ExternalException(result.Errors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Start()
|
||||||
|
{
|
||||||
|
_serviceController.Refresh();
|
||||||
|
|
||||||
|
if (_serviceController.Status != ServiceControllerStatus.Stopped)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_serviceController.Start();
|
||||||
|
_serviceController.WaitForStatus(ServiceControllerStatus.Running);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Stop()
|
||||||
|
{
|
||||||
|
_serviceController.Refresh();
|
||||||
|
|
||||||
|
if (_serviceController.Status != ServiceControllerStatus.Running)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_serviceController.Stop();
|
||||||
|
_serviceController.WaitForStatus(ServiceControllerStatus.Stopped);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Restart()
|
||||||
|
{
|
||||||
|
Stop();
|
||||||
|
Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsRunning()
|
||||||
|
{
|
||||||
|
_serviceController.Refresh();
|
||||||
|
return _serviceController.Status == ServiceControllerStatus.Running;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool GetAutostart()
|
||||||
|
{
|
||||||
|
_serviceController.Refresh();
|
||||||
|
return _serviceController.StartType == ServiceStartMode.Automatic;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetAutostart(bool autostart)
|
||||||
|
{
|
||||||
|
var param = autostart ? "SERVICE_AUTO_START" : "SERVICE_DEMAND_START";
|
||||||
|
var result = RunNssmProcess($"set MicroSocks Start {param}");
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(result.Errors))
|
||||||
|
{
|
||||||
|
throw new ExternalException(result.Errors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IServiceManager.Arguments GetArguments()
|
||||||
|
{
|
||||||
|
var result = RunNssmProcess("get MicroSocks AppParameters");
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(result.Errors))
|
||||||
|
{
|
||||||
|
throw new ExternalException(result.Errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ParseArguments(result.Output);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetArguments(IServiceManager.Arguments arguments)
|
||||||
|
{
|
||||||
|
var result = RunNssmProcess($"set MicroSocks AppParameters -i {arguments.Ip} -p {arguments.Port}");
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(result.Errors))
|
||||||
|
{
|
||||||
|
throw new ExternalException(result.Errors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private IServiceManager.Arguments ParseArguments(string arguments)
|
||||||
|
{
|
||||||
|
var argumentsList = arguments.Split();
|
||||||
|
return new IServiceManager.Arguments(argumentsList[1], argumentsList[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private NssmResult RunNssmProcess(string arguments)
|
||||||
|
{
|
||||||
|
using var process = new Process();
|
||||||
|
|
||||||
|
process.StartInfo = new ProcessStartInfo
|
||||||
|
{
|
||||||
|
FileName = ".\\nssm.exe",
|
||||||
|
Arguments = arguments,
|
||||||
|
UseShellExecute = false,
|
||||||
|
RedirectStandardOutput = true,
|
||||||
|
RedirectStandardError = true,
|
||||||
|
CreateNoWindow = true,
|
||||||
|
WorkingDirectory = Path.GetDirectoryName(".")
|
||||||
|
};
|
||||||
|
|
||||||
|
process.Start();
|
||||||
|
|
||||||
|
var output = process.StandardOutput.ReadToEnd().Replace("\0", "").Trim();
|
||||||
|
var errors = process.StandardError.ReadToEnd().Replace("\0", "").Trim();
|
||||||
|
|
||||||
|
process.WaitForExit();
|
||||||
|
|
||||||
|
return new NssmResult(output, errors);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,155 +1,60 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
|
||||||
using System.Management;
|
|
||||||
using System.Runtime.Versioning;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using ReactiveUI;
|
|
||||||
using ReactiveUI.SourceGenerators;
|
using ReactiveUI.SourceGenerators;
|
||||||
using System.ServiceProcess;
|
using MicrosocksGUI.Services;
|
||||||
|
|
||||||
namespace MicrosocksGUI.ViewModels;
|
namespace MicrosocksGUI.ViewModels;
|
||||||
|
|
||||||
public partial class MainWindowViewModel : ViewModelBase
|
public partial class MainWindowViewModel : ViewModelBase
|
||||||
{
|
{
|
||||||
private record Arguments(string Ip, string Port);
|
[Reactive] private bool _isRunning;
|
||||||
|
[Reactive] private bool _isAutostart;
|
||||||
[Reactive] private bool _isWorking;
|
[Reactive] private string _ip = string.Empty;
|
||||||
[Reactive] private bool _isAutoloading;
|
[Reactive] private string _port = string.Empty;
|
||||||
[Reactive] private string? _ip;
|
|
||||||
[Reactive] private string? _port;
|
private bool _isUpdateLocked;
|
||||||
|
|
||||||
private Timer _timer;
|
private Timer _timer;
|
||||||
//private readonly ManagementObject _serviceManager = new("Win32_Service.Name='Microsocks'");
|
private readonly IServiceManager _serviceManager = new WindowsServiceManager();
|
||||||
private readonly ServiceController _sc = new("MicroSocks");
|
|
||||||
|
|
||||||
public MainWindowViewModel()
|
public MainWindowViewModel()
|
||||||
{
|
{
|
||||||
// TODO Костыль, таймер запускается через секунду, а должен после инициализации ReactiveUI
|
_serviceManager.CreateIfNotExists();
|
||||||
_timer = new Timer(GetServiceStatus, null, TimeSpan.FromSeconds(1), TimeSpan.FromMilliseconds(100));
|
_timer = new Timer(GetServiceStatus, null, TimeSpan.FromSeconds(1), TimeSpan.FromMilliseconds(100));
|
||||||
|
|
||||||
GetMicroSocksArguments();
|
GetMicroSocksArguments();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void GetServiceStatus(object? state)
|
||||||
|
{
|
||||||
|
if (_isUpdateLocked) return;
|
||||||
|
|
||||||
|
IsRunning = _serviceManager.IsRunning();
|
||||||
|
IsAutostart = _serviceManager.GetAutostart();
|
||||||
|
}
|
||||||
|
|
||||||
[ReactiveCommand]
|
[ReactiveCommand]
|
||||||
private void SetServiceStatus()
|
private void SetServiceStatus()
|
||||||
{
|
{
|
||||||
/*var serviceProps = _serviceManager.GetMethodParameters("Change");
|
_isUpdateLocked = true;
|
||||||
serviceProps["StartMode"] = IsAutoloading ? "Automatic" : "Manual";
|
|
||||||
_serviceManager.InvokeMethod("Change", serviceProps, null);*/
|
|
||||||
|
|
||||||
SetServiceAutoloading(IsAutoloading);
|
|
||||||
|
|
||||||
|
|
||||||
if (IsWorking)
|
_serviceManager.SetAutostart(IsAutostart);
|
||||||
|
|
||||||
|
if (IsRunning)
|
||||||
{
|
{
|
||||||
StartService();
|
_serviceManager.Start();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
StopService();
|
_serviceManager.Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//_serviceManager.InvokeMethod(IsWorking ? "StartService" : "StopService", null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void StartService()
|
_isUpdateLocked = false;
|
||||||
{
|
|
||||||
_sc.Refresh();
|
|
||||||
if (_sc.Status != ServiceControllerStatus.Stopped) return;
|
|
||||||
|
|
||||||
_sc.Start();
|
|
||||||
_sc.WaitForStatus(ServiceControllerStatus.Running);
|
|
||||||
//_serviceManager.InvokeMethod("StartService", null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void StopService()
|
|
||||||
{
|
|
||||||
_sc.Refresh();
|
|
||||||
if (_sc.Status != ServiceControllerStatus.Running) return;
|
|
||||||
|
|
||||||
_sc.Stop();
|
|
||||||
_sc.WaitForStatus(ServiceControllerStatus.Stopped);
|
|
||||||
//_serviceManager.InvokeMethod("StopService", null, null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RestartService()
|
|
||||||
{
|
|
||||||
StopService();
|
|
||||||
StartService();
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool ServiceIsRunning()
|
|
||||||
{
|
|
||||||
_sc.Refresh();
|
|
||||||
return _sc.Status == ServiceControllerStatus.Running;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool ServiceIsAutoloading()
|
|
||||||
{
|
|
||||||
_sc.Refresh();
|
|
||||||
return _sc.StartType == ServiceStartMode.Automatic;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetServiceAutoloading(bool isAutoloading)
|
|
||||||
{
|
|
||||||
using var process = new Process();
|
|
||||||
|
|
||||||
var param = isAutoloading ? "SERVICE_AUTO_START" : "SERVICE_DEMAND_START";
|
|
||||||
process.StartInfo = new ProcessStartInfo
|
|
||||||
{
|
|
||||||
FileName = ".\\nssm.exe",
|
|
||||||
Arguments = $"set MicroSocks Start {param}",
|
|
||||||
UseShellExecute = false,
|
|
||||||
RedirectStandardOutput = true,
|
|
||||||
RedirectStandardError = true,
|
|
||||||
CreateNoWindow = true,
|
|
||||||
WorkingDirectory = Path.GetDirectoryName(".")
|
|
||||||
};
|
|
||||||
process.Start();
|
|
||||||
process.WaitForExit();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void GetServiceStatus(object? state)
|
|
||||||
{
|
|
||||||
//_sc.Refresh();
|
|
||||||
//_serviceManager.Get();
|
|
||||||
IsWorking = ServiceIsRunning();
|
|
||||||
IsAutoloading = ServiceIsAutoloading();
|
|
||||||
|
|
||||||
//IsWorking = _serviceManager["State"]?.ToString() == "Running";
|
|
||||||
//IsAutoloading = _serviceManager["StartMode"]?.ToString() == "Auto";
|
|
||||||
}
|
|
||||||
|
|
||||||
Arguments ParseArguments(string arguments)
|
|
||||||
{
|
|
||||||
var argumentsList = arguments.Replace("\0", "").Trim().Split();
|
|
||||||
return new Arguments(argumentsList[1], argumentsList[3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
[ReactiveCommand]
|
[ReactiveCommand]
|
||||||
private void GetMicroSocksArguments()
|
private void GetMicroSocksArguments()
|
||||||
{
|
{
|
||||||
using var process = new Process();
|
var arguments = _serviceManager.GetArguments();
|
||||||
process.StartInfo = new ProcessStartInfo
|
|
||||||
{
|
|
||||||
FileName = ".\\nssm.exe",
|
|
||||||
Arguments = "get MicroSocks AppParameters",
|
|
||||||
UseShellExecute = false,
|
|
||||||
RedirectStandardOutput = true,
|
|
||||||
RedirectStandardError = true,
|
|
||||||
CreateNoWindow = true,
|
|
||||||
WorkingDirectory = Path.GetDirectoryName(".")
|
|
||||||
};
|
|
||||||
|
|
||||||
process.Start();
|
|
||||||
var output = process.StandardOutput.ReadToEnd();
|
|
||||||
process.WaitForExit();
|
|
||||||
|
|
||||||
var arguments = ParseArguments(output);
|
|
||||||
Ip = arguments.Ip;
|
Ip = arguments.Ip;
|
||||||
Port = arguments.Port;
|
Port = arguments.Port;
|
||||||
}
|
}
|
||||||
@ -157,20 +62,7 @@ public partial class MainWindowViewModel : ViewModelBase
|
|||||||
[ReactiveCommand]
|
[ReactiveCommand]
|
||||||
private void SetMicroSocksArguments()
|
private void SetMicroSocksArguments()
|
||||||
{
|
{
|
||||||
using var process = new Process();
|
_serviceManager.SetArguments(new IServiceManager.Arguments(Ip, Port));
|
||||||
process.StartInfo = new ProcessStartInfo
|
_serviceManager.Restart();
|
||||||
{
|
|
||||||
FileName = ".\\nssm.exe",
|
|
||||||
Arguments = $"set MicroSocks AppParameters -i {_ip} -p {_port}",
|
|
||||||
UseShellExecute = false,
|
|
||||||
RedirectStandardOutput = true,
|
|
||||||
RedirectStandardError = true,
|
|
||||||
CreateNoWindow = true,
|
|
||||||
WorkingDirectory = Path.GetDirectoryName(".")
|
|
||||||
};
|
|
||||||
process.Start();
|
|
||||||
process.WaitForExit();
|
|
||||||
|
|
||||||
RestartService();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -11,8 +11,7 @@
|
|||||||
CanMaximize="False"
|
CanMaximize="False"
|
||||||
CanResize="False"
|
CanResize="False"
|
||||||
Width="250"
|
Width="250"
|
||||||
Height="330"
|
Height="330">
|
||||||
>
|
|
||||||
|
|
||||||
<Design.DataContext>
|
<Design.DataContext>
|
||||||
<!-- This only sets the DataContext for the previewer in an IDE,
|
<!-- This only sets the DataContext for the previewer in an IDE,
|
||||||
@ -28,7 +27,7 @@
|
|||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
HorizontalContentAlignment="Center"
|
HorizontalContentAlignment="Center"
|
||||||
IsChecked="{Binding IsWorking}"
|
IsChecked="{Binding IsRunning}"
|
||||||
Command="{Binding SetServiceStatusCommand}">
|
Command="{Binding SetServiceStatusCommand}">
|
||||||
Работа
|
Работа
|
||||||
</ToggleButton>
|
</ToggleButton>
|
||||||
@ -37,7 +36,7 @@
|
|||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
HorizontalContentAlignment="Center"
|
HorizontalContentAlignment="Center"
|
||||||
IsChecked="{Binding IsAutoloading}"
|
IsChecked="{Binding IsAutostart}"
|
||||||
Command="{Binding SetServiceStatusCommand}">
|
Command="{Binding SetServiceStatusCommand}">
|
||||||
Автозапуск
|
Автозапуск
|
||||||
</ToggleButton>
|
</ToggleButton>
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Input;
|
||||||
|
|
||||||
namespace MicrosocksGUI.Views;
|
namespace MicrosocksGUI.Views;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user