Optimize and improve, encapsulate ProcessService

This commit is contained in:
2dust
2025-10-01 19:49:28 +08:00
parent e970372a9f
commit 5b12c36da5
4 changed files with 255 additions and 127 deletions
@@ -0,0 +1,194 @@
using System.Diagnostics;
using System.Text;
namespace ServiceLib.Services;
public class ProcessService : IDisposable
{
private readonly Process _process;
private readonly Func<bool, string, Task>? _updateFunc;
private bool _isDisposed;
public int Id => _process.Id;
public IntPtr Handle => _process.Handle;
public bool HasExited => _process.HasExited;
public ProcessService(
string fileName,
string arguments,
string workingDirectory,
bool displayLog,
bool redirectInput,
Dictionary<string, string>? environmentVars,
Func<bool, string, Task>? updateFunc)
{
_updateFunc = updateFunc;
_process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = fileName,
Arguments = arguments,
WorkingDirectory = workingDirectory,
UseShellExecute = false,
RedirectStandardInput = redirectInput,
RedirectStandardOutput = displayLog,
RedirectStandardError = displayLog,
CreateNoWindow = true,
StandardOutputEncoding = displayLog ? Encoding.UTF8 : null,
StandardErrorEncoding = displayLog ? Encoding.UTF8 : null,
},
EnableRaisingEvents = true
};
if (environmentVars != null)
{
foreach (var kv in environmentVars)
{
_process.StartInfo.Environment[kv.Key] = kv.Value;
}
}
if (displayLog)
{
RegisterEventHandlers();
}
}
public async Task StartAsync(string pwd = null)
{
_process.Start();
if (_process.StartInfo.RedirectStandardOutput)
{
_process.BeginOutputReadLine();
_process.BeginErrorReadLine();
}
if (_process.StartInfo.RedirectStandardInput)
{
await Task.Delay(10);
await _process.StandardInput.WriteLineAsync(pwd);
}
}
public async Task StopAsync()
{
if (_process.HasExited)
{
return;
}
try
{
if (_process.StartInfo.RedirectStandardOutput)
{
try
{
_process.CancelOutputRead();
}
catch
{
throw;
}
try
{
_process.CancelErrorRead();
}
catch
{
throw;
}
}
try
{
if (Utils.IsNonWindows())
{
_process.Kill(true);
}
}
catch
{
throw;
}
try
{
_process.Kill();
}
catch
{
throw;
}
await Task.Delay(100);
}
catch (Exception ex)
{
await _updateFunc?.Invoke(true, ex.Message);
}
}
private void RegisterEventHandlers()
{
void dataHandler(object sender, DataReceivedEventArgs e)
{
if (e.Data.IsNotEmpty())
{
_ = _updateFunc?.Invoke(false, e.Data + Environment.NewLine);
}
}
_process.OutputDataReceived += dataHandler;
_process.ErrorDataReceived += dataHandler;
_process.Exited += (s, e) =>
{
try
{
_process.OutputDataReceived -= dataHandler;
_process.ErrorDataReceived -= dataHandler;
}
catch
{
}
};
}
public void Dispose()
{
if (_isDisposed)
{
return;
}
try
{
if (!_process.HasExited)
{
try
{
_process.CancelOutputRead();
}
catch { }
try
{
_process.CancelErrorRead();
}
catch { }
_process.Kill();
}
_process.Dispose();
}
catch (Exception ex)
{
_updateFunc?.Invoke(true, ex.Message);
}
_isDisposed = true;
}
}
+8 -14
View File
@@ -182,11 +182,11 @@ public class SpeedtestService(Config config, Func<SpeedTestResult, Task> updateF
private async Task<bool> RunRealPingAsync(List<ServerTestItem> selecteds, string exitLoopKey)
{
var pid = -1;
ProcessService processService = null;
try
{
pid = await CoreManager.Instance.LoadCoreConfigSpeedtest(selecteds);
if (pid < 0)
processService = await CoreManager.Instance.LoadCoreConfigSpeedtest(selecteds);
if (processService is null)
{
return false;
}
@@ -216,10 +216,7 @@ public class SpeedtestService(Config config, Func<SpeedTestResult, Task> updateF
}
finally
{
if (pid > 0)
{
await ProcUtils.ProcessKill(pid);
}
await processService?.StopAsync();
}
return true;
}
@@ -244,11 +241,11 @@ public class SpeedtestService(Config config, Func<SpeedTestResult, Task> updateF
tasks.Add(Task.Run(async () =>
{
var pid = -1;
ProcessService processService = null;
try
{
pid = await CoreManager.Instance.LoadCoreConfigSpeedtest(it);
if (pid < 0)
processService = await CoreManager.Instance.LoadCoreConfigSpeedtest(it);
if (processService is null)
{
await UpdateFunc(it.IndexId, "", ResUI.FailedToRunCore);
}
@@ -275,10 +272,7 @@ public class SpeedtestService(Config config, Func<SpeedTestResult, Task> updateF
}
finally
{
if (pid > 0)
{
await ProcUtils.ProcessKill(pid);
}
await processService?.StopAsync();
concurrencySemaphore.Release();
}
}));