LANCommander/LANCommander.SDK/RedistributableManager.cs

185 lines
6.6 KiB
C#
Raw Permalink Normal View History

using LANCommander.SDK.Enums;
using LANCommander.SDK.Extensions;
using LANCommander.SDK.Helpers;
using LANCommander.SDK.Models;
using LANCommander.SDK.PowerShell;
using Microsoft.Extensions.Logging;
using SharpCompress.Common;
using SharpCompress.Readers;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace LANCommander.SDK
{
public class RedistributableManager
{
2023-11-11 02:53:48 +00:00
private readonly ILogger Logger;
private Client Client { get; set; }
public delegate void OnArchiveEntryExtractionProgressHandler(object sender, ArchiveEntryExtractionProgressArgs e);
public event OnArchiveEntryExtractionProgressHandler OnArchiveEntryExtractionProgress;
public delegate void OnArchiveExtractionProgressHandler(long position, long length);
public event OnArchiveExtractionProgressHandler OnArchiveExtractionProgress;
public RedistributableManager(Client client)
{
Client = client;
}
2023-11-11 02:53:48 +00:00
public RedistributableManager(Client client, ILogger logger)
{
Client = client;
Logger = logger;
}
public void Install(Game game)
{
foreach (var redistributable in game.Redistributables)
{
Install(redistributable);
}
}
public void Install(Redistributable redistributable)
{
string installScriptTempFile = null;
string detectionScriptTempFile = null;
string extractTempPath = null;
try
{
var installScript = redistributable.Scripts.FirstOrDefault(s => s.Type == ScriptType.Install);
installScriptTempFile = ScriptHelper.SaveTempScript(installScript);
var detectionScript = redistributable.Scripts.FirstOrDefault(s => s.Type == ScriptType.DetectInstall);
detectionScriptTempFile = ScriptHelper.SaveTempScript(detectionScript);
var detectionResult = RunScript(detectionScriptTempFile, redistributable, detectionScript.RequiresAdmin);
// Redistributable is not installed
if (detectionResult == 0)
{
if (redistributable.Archives.Count() > 0)
{
var extractionResult = DownloadAndExtract(redistributable);
if (extractionResult.Success)
{
extractTempPath = extractionResult.Directory;
RunScript(installScriptTempFile, redistributable, installScript.RequiresAdmin, extractTempPath);
}
}
else
{
RunScript(installScriptTempFile, redistributable, installScript.RequiresAdmin, extractTempPath);
}
}
}
catch (Exception ex)
{
2023-11-11 02:53:28 +00:00
Logger?.LogError(ex, "Redistributable {Redistributable} failed to install", redistributable.Name);
}
finally
{
if (File.Exists(installScriptTempFile))
File.Delete(installScriptTempFile);
if (File.Exists(detectionScriptTempFile))
File.Delete(detectionScriptTempFile);
if (Directory.Exists(extractTempPath))
Directory.Delete(extractTempPath);
}
}
private ExtractionResult DownloadAndExtract(Redistributable redistributable)
{
if (redistributable == null)
{
2023-11-11 02:53:28 +00:00
Logger?.LogTrace("Redistributable failed to download! No redistributable was specified");
throw new ArgumentNullException("No redistributable was specified");
}
var destination = Path.Combine(Path.GetTempPath(), redistributable.Name.SanitizeFilename());
2023-11-11 02:53:28 +00:00
Logger?.LogTrace("Downloading and extracting {Redistributable} to path {Destination}", redistributable.Name, destination);
try
{
Directory.CreateDirectory(destination);
using (var redistributableStream = Client.StreamRedistributable(redistributable.Id))
using (var reader = ReaderFactory.Open(redistributableStream))
{
redistributableStream.OnProgress += (pos, len) =>
{
OnArchiveExtractionProgress?.Invoke(pos, len);
};
reader.EntryExtractionProgress += (object sender, ReaderExtractionEventArgs<IEntry> e) =>
{
OnArchiveEntryExtractionProgress?.Invoke(this, new ArchiveEntryExtractionProgressArgs
{
Entry = e.Item,
Progress = e.ReaderProgress,
});
};
reader.WriteAllToDirectory(destination, new ExtractionOptions()
{
ExtractFullPath = true,
Overwrite = true
});
}
}
catch (Exception ex)
{
2023-11-11 02:53:28 +00:00
Logger?.LogError(ex, "Could not extract to path {Destination}", destination);
if (Directory.Exists(destination))
{
2023-11-11 02:53:28 +00:00
Logger?.LogTrace("Cleaning up orphaned files after bad install");
Directory.Delete(destination, true);
}
throw new Exception("The redistributable archive could not be extracted, is it corrupted? Please try again");
}
var extractionResult = new ExtractionResult
{
Canceled = false
};
if (!extractionResult.Canceled)
{
extractionResult.Success = true;
extractionResult.Directory = destination;
2023-11-11 02:53:28 +00:00
Logger?.LogTrace("Redistributable {Redistributable} successfully downloaded and extracted to {Destination}", redistributable.Name, destination);
}
return extractionResult;
}
private int RunScript(string path, Redistributable redistributable, bool requiresAdmin = false, string workingDirectory = "")
{
var script = new PowerShellScript();
script.AddVariable("Redistributable", redistributable);
script.UseWorkingDirectory(workingDirectory);
script.UseFile(path);
if (requiresAdmin)
script.RunAsAdmin();
return script.Execute();
}
}
}