mirror of
https://github.com/chylex/Minecraft-Phantom-Panel.git
synced 2025-05-04 09:34:05 +02:00
Extract reusable one-shot process runner from backup compressor implementation
This commit is contained in:
parent
bb7de48d24
commit
d93c93cbf7
@ -1,15 +1,17 @@
|
||||
using System.Diagnostics;
|
||||
using Phantom.Common.Logging;
|
||||
using Phantom.Utils.Runtime;
|
||||
using Serilog;
|
||||
|
||||
namespace Phantom.Agent.Services.Backups;
|
||||
|
||||
static class BackupCompressor {
|
||||
private static ILogger Logger { get; } = PhantomLogger.Create(nameof(BackupCompressor));
|
||||
private static ILogger ZstdLogger { get; } = PhantomLogger.Create(nameof(BackupCompressor), "Zstd");
|
||||
|
||||
private const int Quality = 10;
|
||||
private const int Memory = 26;
|
||||
private const int Threads = 3;
|
||||
private const string Quality = "-10";
|
||||
private const string Memory = "--long=26";
|
||||
private const string Threads = "-T3";
|
||||
|
||||
public static async Task<string?> Compress(string sourceFilePath, CancellationToken cancellationToken) {
|
||||
if (sourceFilePath.Contains('"')) {
|
||||
@ -38,66 +40,31 @@ static class BackupCompressor {
|
||||
Logger.Error("Invalid destination path: {Path}", destinationFilePath);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
var startInfo = new ProcessStartInfo {
|
||||
FileName = "zstd",
|
||||
WorkingDirectory = workingDirectory,
|
||||
Arguments = $"-{Quality} --long={Memory} -T{Threads} -c --rm --no-progress -c -o \"{destinationFilePath}\" -- \"{sourceFilePath}\"",
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true
|
||||
ArgumentList = {
|
||||
Quality,
|
||||
Memory,
|
||||
Threads,
|
||||
"-c",
|
||||
"--rm",
|
||||
"--no-progress",
|
||||
"-c",
|
||||
"-o", destinationFilePath,
|
||||
"--", sourceFilePath
|
||||
}
|
||||
};
|
||||
|
||||
using var process = new Process { StartInfo = startInfo };
|
||||
process.OutputDataReceived += OnZstdProcessOutput;
|
||||
process.ErrorDataReceived += OnZstdProcessOutput;
|
||||
|
||||
try {
|
||||
process.Start();
|
||||
process.BeginOutputReadLine();
|
||||
process.BeginErrorReadLine();
|
||||
} catch (Exception e) {
|
||||
Logger.Error(e, "Caught exception launching zstd process.");
|
||||
static void OnZstdOutput(object? sender, DataReceivedEventArgs e) {
|
||||
if (!string.IsNullOrWhiteSpace(e.Data)) {
|
||||
ZstdLogger.Verbose("[Output] {Line}", e.Data);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
await process.WaitForExitAsync(cancellationToken);
|
||||
} catch (OperationCanceledException) {
|
||||
await TryKillProcess(process);
|
||||
return false;
|
||||
} catch (Exception e) {
|
||||
Logger.Error(e, "Caught exception waiting for zstd process to exit.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!process.HasExited) {
|
||||
await TryKillProcess(process);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (process.ExitCode != 0) {
|
||||
Logger.Error("Zstd process exited with code {ExitCode}.", process.ExitCode);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void OnZstdProcessOutput(object sender, DataReceivedEventArgs e) {
|
||||
if (!string.IsNullOrWhiteSpace(e.Data)) {
|
||||
Logger.Verbose("[Zstd] {Line}", e.Data);
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task TryKillProcess(Process process) {
|
||||
CancellationTokenSource timeout = new CancellationTokenSource(TimeSpan.FromSeconds(1));
|
||||
|
||||
try {
|
||||
process.Kill();
|
||||
await process.WaitForExitAsync(timeout.Token);
|
||||
} catch (OperationCanceledException) {
|
||||
Logger.Error("Timed out waiting for killed zstd process to exit.");
|
||||
} catch (Exception e) {
|
||||
Logger.Error(e, "Caught exception killing zstd process.");
|
||||
}
|
||||
var process = new OneShotProcess(ZstdLogger, startInfo);
|
||||
process.Output += OnZstdOutput;
|
||||
return await process.Run(cancellationToken);
|
||||
}
|
||||
}
|
||||
|
69
Utils/Phantom.Utils.Runtime/OneShotProcess.cs
Normal file
69
Utils/Phantom.Utils.Runtime/OneShotProcess.cs
Normal file
@ -0,0 +1,69 @@
|
||||
using System.Diagnostics;
|
||||
using Serilog;
|
||||
|
||||
namespace Phantom.Utils.Runtime;
|
||||
|
||||
public sealed class OneShotProcess {
|
||||
private readonly ILogger logger;
|
||||
private readonly ProcessStartInfo startInfo;
|
||||
|
||||
public event DataReceivedEventHandler? Output;
|
||||
|
||||
public OneShotProcess(ILogger logger, ProcessStartInfo startInfo) {
|
||||
this.logger = logger;
|
||||
this.startInfo = startInfo;
|
||||
this.startInfo.RedirectStandardOutput = true;
|
||||
this.startInfo.RedirectStandardError = true;
|
||||
}
|
||||
|
||||
public async Task<bool> Run(CancellationToken cancellationToken) {
|
||||
using var process = new Process { StartInfo = startInfo };
|
||||
process.OutputDataReceived += Output;
|
||||
process.ErrorDataReceived += Output;
|
||||
|
||||
try {
|
||||
process.Start();
|
||||
process.BeginOutputReadLine();
|
||||
process.BeginErrorReadLine();
|
||||
} catch (Exception e) {
|
||||
logger.Error(e, "Caught exception launching process.");
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
await process.WaitForExitAsync(cancellationToken);
|
||||
} catch (OperationCanceledException) {
|
||||
await TryKillProcess(process);
|
||||
return false;
|
||||
} catch (Exception e) {
|
||||
logger.Error(e, "Caught exception waiting for process to exit.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!process.HasExited) {
|
||||
await TryKillProcess(process);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (process.ExitCode != 0) {
|
||||
logger.Error("Process exited with code {ExitCode}.", process.ExitCode);
|
||||
return false;
|
||||
}
|
||||
|
||||
logger.Verbose("Process finished successfully.");
|
||||
return true;
|
||||
}
|
||||
|
||||
private async Task TryKillProcess(Process process) {
|
||||
using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(2));
|
||||
|
||||
try {
|
||||
process.Kill();
|
||||
await process.WaitForExitAsync(timeout.Token);
|
||||
} catch (OperationCanceledException) {
|
||||
logger.Error("Timed out waiting for killed process to exit.");
|
||||
} catch (Exception e) {
|
||||
logger.Error(e, "Caught exception killing process.");
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user