release
This commit is contained in:
@ -1,5 +1,6 @@
|
||||
<Application xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:dialogHostAvalonia="clr-namespace:DialogHostAvalonia;assembly=DialogHost.Avalonia"
|
||||
x:Class="MicrosocksGUI.App"
|
||||
xmlns:local="using:MicrosocksGUI"
|
||||
RequestedThemeVariant="Default">
|
||||
@ -11,5 +12,6 @@
|
||||
|
||||
<Application.Styles>
|
||||
<FluentTheme />
|
||||
<dialogHostAvalonia:DialogHostStyles />
|
||||
</Application.Styles>
|
||||
</Application>
|
||||
@ -22,6 +22,7 @@
|
||||
<IncludeAssets Condition="'$(Configuration)' != 'Debug'">None</IncludeAssets>
|
||||
<PrivateAssets Condition="'$(Configuration)' != 'Debug'">All</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="DialogHost.Avalonia" Version="0.10.0" />
|
||||
<PackageReference Include="ReactiveUI.Avalonia" Version="11.3.8"/>
|
||||
<PackageReference Include="ReactiveUI.SourceGenerators" Version="2.5.1">
|
||||
<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.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Management;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using ReactiveUI;
|
||||
using ReactiveUI.SourceGenerators;
|
||||
using System.ServiceProcess;
|
||||
using MicrosocksGUI.Services;
|
||||
|
||||
namespace MicrosocksGUI.ViewModels;
|
||||
|
||||
public partial class MainWindowViewModel : ViewModelBase
|
||||
{
|
||||
private record Arguments(string Ip, string Port);
|
||||
|
||||
[Reactive] private bool _isWorking;
|
||||
[Reactive] private bool _isAutoloading;
|
||||
[Reactive] private string? _ip;
|
||||
[Reactive] private string? _port;
|
||||
[Reactive] private bool _isRunning;
|
||||
[Reactive] private bool _isAutostart;
|
||||
[Reactive] private string _ip = string.Empty;
|
||||
[Reactive] private string _port = string.Empty;
|
||||
|
||||
private bool _isUpdateLocked;
|
||||
|
||||
private Timer _timer;
|
||||
//private readonly ManagementObject _serviceManager = new("Win32_Service.Name='Microsocks'");
|
||||
private readonly ServiceController _sc = new("MicroSocks");
|
||||
private readonly IServiceManager _serviceManager = new WindowsServiceManager();
|
||||
|
||||
public MainWindowViewModel()
|
||||
{
|
||||
// TODO Костыль, таймер запускается через секунду, а должен после инициализации ReactiveUI
|
||||
_serviceManager.CreateIfNotExists();
|
||||
_timer = new Timer(GetServiceStatus, null, TimeSpan.FromSeconds(1), TimeSpan.FromMilliseconds(100));
|
||||
|
||||
GetMicroSocksArguments();
|
||||
}
|
||||
|
||||
private void GetServiceStatus(object? state)
|
||||
{
|
||||
if (_isUpdateLocked) return;
|
||||
|
||||
IsRunning = _serviceManager.IsRunning();
|
||||
IsAutostart = _serviceManager.GetAutostart();
|
||||
}
|
||||
|
||||
[ReactiveCommand]
|
||||
private void SetServiceStatus()
|
||||
{
|
||||
/*var serviceProps = _serviceManager.GetMethodParameters("Change");
|
||||
serviceProps["StartMode"] = IsAutoloading ? "Automatic" : "Manual";
|
||||
_serviceManager.InvokeMethod("Change", serviceProps, null);*/
|
||||
|
||||
SetServiceAutoloading(IsAutoloading);
|
||||
|
||||
_isUpdateLocked = true;
|
||||
|
||||
if (IsWorking)
|
||||
_serviceManager.SetAutostart(IsAutostart);
|
||||
|
||||
if (IsRunning)
|
||||
{
|
||||
StartService();
|
||||
_serviceManager.Start();
|
||||
}
|
||||
else
|
||||
{
|
||||
StopService();
|
||||
_serviceManager.Stop();
|
||||
}
|
||||
|
||||
|
||||
|
||||
//_serviceManager.InvokeMethod(IsWorking ? "StartService" : "StopService", null, null);
|
||||
}
|
||||
|
||||
private void StartService()
|
||||
{
|
||||
_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);
|
||||
_isUpdateLocked = false;
|
||||
}
|
||||
|
||||
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]
|
||||
private void GetMicroSocksArguments()
|
||||
{
|
||||
using var process = new Process();
|
||||
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);
|
||||
var arguments = _serviceManager.GetArguments();
|
||||
Ip = arguments.Ip;
|
||||
Port = arguments.Port;
|
||||
}
|
||||
@ -157,20 +62,7 @@ public partial class MainWindowViewModel : ViewModelBase
|
||||
[ReactiveCommand]
|
||||
private void SetMicroSocksArguments()
|
||||
{
|
||||
using var process = new Process();
|
||||
process.StartInfo = new ProcessStartInfo
|
||||
{
|
||||
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();
|
||||
_serviceManager.SetArguments(new IServiceManager.Arguments(Ip, Port));
|
||||
_serviceManager.Restart();
|
||||
}
|
||||
}
|
||||
@ -11,8 +11,7 @@
|
||||
CanMaximize="False"
|
||||
CanResize="False"
|
||||
Width="250"
|
||||
Height="330"
|
||||
>
|
||||
Height="330">
|
||||
|
||||
<Design.DataContext>
|
||||
<!-- This only sets the DataContext for the previewer in an IDE,
|
||||
@ -28,7 +27,7 @@
|
||||
Grid.Column="0"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Center"
|
||||
IsChecked="{Binding IsWorking}"
|
||||
IsChecked="{Binding IsRunning}"
|
||||
Command="{Binding SetServiceStatusCommand}">
|
||||
Работа
|
||||
</ToggleButton>
|
||||
@ -37,7 +36,7 @@
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Center"
|
||||
IsChecked="{Binding IsAutoloading}"
|
||||
IsChecked="{Binding IsAutostart}"
|
||||
Command="{Binding SetServiceStatusCommand}">
|
||||
Автозапуск
|
||||
</ToggleButton>
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
|
||||
namespace MicrosocksGUI.Views;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user