mirror of
https://github.com/tgstation/tgstation-server.git
synced 2026-08-27 07:04:57 +01:00
Deduplicate download code for IByondInstallers
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Tgstation.Server.Host.IO;
|
||||
|
||||
namespace Tgstation.Server.Host.Components.Byond
|
||||
{
|
||||
/// <inheritdoc />
|
||||
abstract class ByondInstallerBase : IByondInstaller
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public abstract string DreamDaemonName { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public abstract string DreamMakerName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the URL formatter string for downloading a byond version of {0:Major} {1:Minor}.
|
||||
/// </summary>
|
||||
protected abstract string ByondRevisionsURLTemplate { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="IIOManager"/> for the <see cref="ByondInstallerBase"/>.
|
||||
/// </summary>
|
||||
protected IIOManager IOManager { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="ILogger"/> for the <see cref="ByondInstallerBase"/>.
|
||||
/// </summary>
|
||||
protected ILogger<ByondInstallerBase> Logger { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ByondInstallerBase"/> <see langword="class"/>.
|
||||
/// </summary>
|
||||
/// <param name="ioManager">The value of <see cref="IOManager"/>.</param>
|
||||
/// <param name="logger">The value of <see cref="Logger"/>.</param>
|
||||
protected ByondInstallerBase(IIOManager ioManager, ILogger<ByondInstallerBase> logger)
|
||||
{
|
||||
IOManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager));
|
||||
Logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public abstract Task CleanCache(CancellationToken cancellationToken);
|
||||
|
||||
/// <inheritdoc />
|
||||
public abstract Task InstallByond(string path, Version version, CancellationToken cancellationToken);
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<byte[]> DownloadVersion(Version version, CancellationToken cancellationToken)
|
||||
{
|
||||
if (version == null)
|
||||
throw new ArgumentNullException(nameof(version));
|
||||
|
||||
var url = String.Format(CultureInfo.InvariantCulture, ByondRevisionsURLTemplate, version.Major, version.Minor);
|
||||
|
||||
Logger.LogTrace("Downloading from: {0}", url);
|
||||
|
||||
return IOManager.DownloadFile(new Uri(url), cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,13 +11,8 @@ namespace Tgstation.Server.Host.Components.Byond
|
||||
/// <summary>
|
||||
/// <see cref="IByondInstaller"/> for Posix systems
|
||||
/// </summary>
|
||||
sealed class PosixByondInstaller : IByondInstaller
|
||||
sealed class PosixByondInstaller : ByondInstallerBase
|
||||
{
|
||||
/// <summary>
|
||||
/// The URL format string for getting BYOND linux version {0}.{1} zipfile
|
||||
/// </summary>
|
||||
const string ByondRevisionsURLTemplate = "https://secure.byond.com/download/build/{0}/{0}.{1}_byond_linux.zip";
|
||||
|
||||
/// <summary>
|
||||
/// Path to the BYOND cache
|
||||
/// </summary>
|
||||
@@ -28,45 +23,37 @@ namespace Tgstation.Server.Host.Components.Byond
|
||||
const string ShellScriptExtension = ".sh";
|
||||
|
||||
/// <inheritdoc />
|
||||
public string DreamDaemonName => DreamDaemonExecutableName + ShellScriptExtension;
|
||||
public override string DreamDaemonName => DreamDaemonExecutableName + ShellScriptExtension;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string DreamMakerName => DreamMakerExecutableName + ShellScriptExtension;
|
||||
public override string DreamMakerName => DreamMakerExecutableName + ShellScriptExtension;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IIOManager"/> for the <see cref="PosixByondInstaller"/>
|
||||
/// </summary>
|
||||
readonly IIOManager ioManager;
|
||||
/// <inheritdoc />
|
||||
protected override string ByondRevisionsURLTemplate => "https://secure.byond.com/download/build/{0}/{0}.{1}_byond_linux.zip";
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IPostWriteHandler"/> for the <see cref="PosixByondInstaller"/>
|
||||
/// </summary>
|
||||
readonly IPostWriteHandler postWriteHandler;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="ILogger"/> for the <see cref="PosixByondInstaller"/>
|
||||
/// </summary>
|
||||
readonly ILogger<PosixByondInstaller> logger;
|
||||
|
||||
/// <summary>
|
||||
/// Construct a <see cref="WindowsByondInstaller"/>
|
||||
/// </summary>
|
||||
/// <param name="ioManager">The value of <see cref="ioManager"/></param>
|
||||
/// <param name="postWriteHandler">The value of <see cref="postWriteHandler"/></param>
|
||||
/// <param name="logger">The value of <see cref="logger"/></param>
|
||||
public PosixByondInstaller(IIOManager ioManager, IPostWriteHandler postWriteHandler, ILogger<PosixByondInstaller> logger)
|
||||
/// <param name="ioManager">The <see cref="IIOManager"/> for the <see cref="ByondInstallerBase"/>.</param>
|
||||
/// <param name="logger">The <see cref="ILogger"/> for the <see cref="ByondInstallerBase"/>.</param>
|
||||
public PosixByondInstaller(IPostWriteHandler postWriteHandler, IIOManager ioManager, ILogger<PosixByondInstaller> logger)
|
||||
: base(ioManager, logger)
|
||||
{
|
||||
this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager));
|
||||
this.postWriteHandler = postWriteHandler ?? throw new ArgumentNullException(nameof(postWriteHandler));
|
||||
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task CleanCache(CancellationToken cancellationToken)
|
||||
public override async Task CleanCache(CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
await ioManager.DeleteDirectory(ByondCachePath, cancellationToken).ConfigureAwait(false);
|
||||
await IOManager.DeleteDirectory(ByondCachePath, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
@@ -74,23 +61,12 @@ namespace Tgstation.Server.Host.Components.Byond
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.LogWarning("Error deleting BYOND cache! Exception: {0}", e);
|
||||
Logger.LogWarning("Error deleting BYOND cache! Exception: {0}", e);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<byte[]> DownloadVersion(Version version, CancellationToken cancellationToken)
|
||||
{
|
||||
if (version == null)
|
||||
throw new ArgumentNullException(nameof(version));
|
||||
|
||||
var url = String.Format(CultureInfo.InvariantCulture, ByondRevisionsURLTemplate, version.Major, version.Minor);
|
||||
|
||||
return await ioManager.DownloadFile(new Uri(url), cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task InstallByond(string path, Version version, CancellationToken cancellationToken)
|
||||
public override Task InstallByond(string path, Version version, CancellationToken cancellationToken)
|
||||
{
|
||||
if (path == null)
|
||||
throw new ArgumentNullException(nameof(path));
|
||||
@@ -106,16 +82,16 @@ namespace Tgstation.Server.Host.Components.Byond
|
||||
|
||||
async Task WriteAndMakeExecutable(string fullPath, string script)
|
||||
{
|
||||
await ioManager.WriteAllBytes(fullPath, Encoding.ASCII.GetBytes(script), cancellationToken).ConfigureAwait(false);
|
||||
await IOManager.WriteAllBytes(fullPath, Encoding.ASCII.GetBytes(script), cancellationToken).ConfigureAwait(false);
|
||||
postWriteHandler.HandleWrite(fullPath);
|
||||
}
|
||||
|
||||
var basePath = ioManager.ConcatPath(path, ByondManager.BinPath);
|
||||
var basePath = IOManager.ConcatPath(path, ByondManager.BinPath);
|
||||
|
||||
var task = Task.WhenAll(WriteAndMakeExecutable(ioManager.ConcatPath(basePath, DreamDaemonName), dreamDaemonScript), WriteAndMakeExecutable(ioManager.ConcatPath(basePath, DreamMakerName), dreamMakerScript));
|
||||
var task = Task.WhenAll(WriteAndMakeExecutable(IOManager.ConcatPath(basePath, DreamDaemonName), dreamDaemonScript), WriteAndMakeExecutable(IOManager.ConcatPath(basePath, DreamMakerName), dreamMakerScript));
|
||||
|
||||
postWriteHandler.HandleWrite(ioManager.ConcatPath(basePath, DreamDaemonExecutableName));
|
||||
postWriteHandler.HandleWrite(ioManager.ConcatPath(basePath, DreamMakerExecutableName));
|
||||
postWriteHandler.HandleWrite(IOManager.ConcatPath(basePath, DreamDaemonExecutableName));
|
||||
postWriteHandler.HandleWrite(IOManager.ConcatPath(basePath, DreamMakerExecutableName));
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
@@ -12,13 +12,8 @@ namespace Tgstation.Server.Host.Components.Byond
|
||||
/// <summary>
|
||||
/// <see cref="IByondInstaller"/> for windows systems
|
||||
/// </summary>
|
||||
sealed class WindowsByondInstaller : IByondInstaller, IDisposable
|
||||
sealed class WindowsByondInstaller : ByondInstallerBase, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// The URL format string for getting BYOND windows version {0}.{1} zipfile
|
||||
/// </summary>
|
||||
const string ByondRevisionsURLTemplate = "https://secure.byond.com/download/build/{0}/{0}.{1}_byond.zip";
|
||||
|
||||
/// <summary>
|
||||
/// Directory to byond installation configuration
|
||||
/// </summary>
|
||||
@@ -40,26 +35,19 @@ namespace Tgstation.Server.Host.Components.Byond
|
||||
const string ByondDXDir = "byond/directx";
|
||||
|
||||
/// <inheritdoc />
|
||||
public string DreamDaemonName => "dreamdaemon.exe";
|
||||
public override string DreamDaemonName => "dreamdaemon.exe";
|
||||
|
||||
/// <inheritdoc />
|
||||
public string DreamMakerName => "dm.exe";
|
||||
public override string DreamMakerName => "dm.exe";
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IIOManager"/> for the <see cref="WindowsByondInstaller"/>
|
||||
/// </summary>
|
||||
readonly IIOManager ioManager;
|
||||
/// <inheritdoc />
|
||||
protected override string ByondRevisionsURLTemplate => "https://secure.byond.com/download/build/{0}/{0}.{1}_byond.zip";
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IProcessExecutor"/> for the <see cref="WindowsByondInstaller"/>
|
||||
/// </summary>
|
||||
readonly IProcessExecutor processExecutor;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="ILogger"/> for the <see cref="WindowsByondInstaller"/>
|
||||
/// </summary>
|
||||
readonly ILogger<WindowsByondInstaller> logger;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="SemaphoreSlim"/> for the <see cref="WindowsByondInstaller"/>
|
||||
/// </summary>
|
||||
@@ -73,14 +61,13 @@ namespace Tgstation.Server.Host.Components.Byond
|
||||
/// <summary>
|
||||
/// Construct a <see cref="WindowsByondInstaller"/>
|
||||
/// </summary>
|
||||
/// <param name="ioManager">The value of <see cref="ioManager"/></param>
|
||||
/// <param name="processExecutor">The value of <see cref="processExecutor"/></param>
|
||||
/// <param name="logger">The value of <see cref="logger"/></param>
|
||||
public WindowsByondInstaller(IIOManager ioManager, IProcessExecutor processExecutor, ILogger<WindowsByondInstaller> logger)
|
||||
/// <param name="ioManager">The <see cref="IIOManager"/> for the <see cref="ByondInstallerBase"/>.</param>
|
||||
/// <param name="logger">The <see cref="ILogger"/> for the <see cref="ByondInstallerBase"/>.</param>
|
||||
public WindowsByondInstaller(IProcessExecutor processExecutor, IIOManager ioManager, ILogger<WindowsByondInstaller> logger)
|
||||
: base(ioManager, logger)
|
||||
{
|
||||
this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager));
|
||||
this.processExecutor = processExecutor ?? throw new ArgumentNullException(nameof(processExecutor));
|
||||
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
|
||||
semaphore = new SemaphoreSlim(1);
|
||||
installedDirectX = false;
|
||||
@@ -90,11 +77,11 @@ namespace Tgstation.Server.Host.Components.Byond
|
||||
public void Dispose() => semaphore.Dispose();
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task CleanCache(CancellationToken cancellationToken)
|
||||
public override async Task CleanCache(CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
await ioManager.DeleteDirectory(ioManager.ConcatPath(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "byond/cache"), cancellationToken).ConfigureAwait(false);
|
||||
await IOManager.DeleteDirectory(IOManager.ConcatPath(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "byond/cache"), cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
catch(OperationCanceledException)
|
||||
{
|
||||
@@ -102,26 +89,18 @@ namespace Tgstation.Server.Host.Components.Byond
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.LogWarning("Error deleting BYOND cache! Exception: {0}", e);
|
||||
Logger.LogWarning("Error deleting BYOND cache! Exception: {0}", e);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<byte[]> DownloadVersion(Version version, CancellationToken cancellationToken)
|
||||
{
|
||||
var url = String.Format(CultureInfo.InvariantCulture, ByondRevisionsURLTemplate, version.Major, version.Minor);
|
||||
|
||||
return ioManager.DownloadFile(new Uri(url), cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task InstallByond(string path, Version version, CancellationToken cancellationToken)
|
||||
public override async Task InstallByond(string path, Version version, CancellationToken cancellationToken)
|
||||
{
|
||||
async Task SetNoPromptTrusted()
|
||||
{
|
||||
var configPath = ioManager.ConcatPath(path, ByondConfigDir);
|
||||
await ioManager.CreateDirectory(configPath, cancellationToken).ConfigureAwait(false);
|
||||
await ioManager.WriteAllBytes(ioManager.ConcatPath(configPath, ByondDDConfig), Encoding.UTF8.GetBytes(ByondNoPromptTrustedMode), cancellationToken).ConfigureAwait(false);
|
||||
var configPath = IOManager.ConcatPath(path, ByondConfigDir);
|
||||
await IOManager.CreateDirectory(configPath, cancellationToken).ConfigureAwait(false);
|
||||
await IOManager.WriteAllBytes(IOManager.ConcatPath(configPath, ByondDDConfig), Encoding.UTF8.GetBytes(ByondNoPromptTrustedMode), cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
var setNoPromptTrustedModeTask = SetNoPromptTrusted();
|
||||
@@ -135,13 +114,13 @@ namespace Tgstation.Server.Host.Components.Byond
|
||||
{
|
||||
// ^check again because race conditions
|
||||
// always install it, it's pretty fast and will do better redundancy checking than us
|
||||
var rbdx = ioManager.ConcatPath(path, ByondDXDir);
|
||||
var rbdx = IOManager.ConcatPath(path, ByondDXDir);
|
||||
|
||||
// noShellExecute because we aren't doing runas shennanigans
|
||||
IProcess directXInstaller;
|
||||
try
|
||||
{
|
||||
directXInstaller = processExecutor.LaunchProcess(ioManager.ConcatPath(rbdx, "DXSETUP.exe"), rbdx, "/silent", noShellExecute: true);
|
||||
directXInstaller = processExecutor.LaunchProcess(IOManager.ConcatPath(rbdx, "DXSETUP.exe"), rbdx, "/silent", noShellExecute: true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
@@ -14,22 +14,22 @@ namespace Tgstation.Server.Host.Components.Byond.Tests
|
||||
public void TestConstruction()
|
||||
{
|
||||
Assert.ThrowsException<ArgumentNullException>(() => new PosixByondInstaller(null, null, null));
|
||||
var mockIOManager = new Mock<IIOManager>();
|
||||
Assert.ThrowsException<ArgumentNullException>(() => new PosixByondInstaller(mockIOManager.Object, null, null));
|
||||
var mockPostWriteHandler = new Mock<IPostWriteHandler>();
|
||||
Assert.ThrowsException<ArgumentNullException>(() => new PosixByondInstaller(mockIOManager.Object, mockPostWriteHandler.Object, null));
|
||||
Assert.ThrowsException<ArgumentNullException>(() => new PosixByondInstaller(mockPostWriteHandler.Object, null, null));
|
||||
var mockIOManager = new Mock<IIOManager>();
|
||||
Assert.ThrowsException<ArgumentNullException>(() => new PosixByondInstaller(mockPostWriteHandler.Object, mockIOManager.Object, null));
|
||||
|
||||
var mockLogger = new Mock<ILogger<PosixByondInstaller>>();
|
||||
new PosixByondInstaller(mockIOManager.Object, mockPostWriteHandler.Object, mockLogger.Object);
|
||||
new PosixByondInstaller(mockPostWriteHandler.Object, mockIOManager.Object, mockLogger.Object);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task TestCacheClean()
|
||||
{
|
||||
var mockIOManager = new Mock<IIOManager>();
|
||||
var mockPostWriteHandler = new Mock<IPostWriteHandler>();
|
||||
var mockIOManager = new Mock<IIOManager>();
|
||||
var mockLogger = new Mock<ILogger<PosixByondInstaller>>();
|
||||
var installer = new PosixByondInstaller(mockIOManager.Object, mockPostWriteHandler.Object, mockLogger.Object);
|
||||
var installer = new PosixByondInstaller(mockPostWriteHandler.Object, mockIOManager.Object, mockLogger.Object);
|
||||
|
||||
const string ByondCachePath = "~/.byond/cache";
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace Tgstation.Server.Host.Components.Byond.Tests
|
||||
|
||||
await installer.CleanCache(default);
|
||||
|
||||
mockIOManager.Verify();
|
||||
mockPostWriteHandler.Verify();
|
||||
|
||||
|
||||
mockIOManager.Setup(x => x.DeleteDirectory(ByondCachePath, default)).Throws(new OperationCanceledException()).Verifiable();
|
||||
@@ -60,7 +60,7 @@ namespace Tgstation.Server.Host.Components.Byond.Tests
|
||||
var mockIOManager = new Mock<IIOManager>();
|
||||
var mockPostWriteHandler = new Mock<IPostWriteHandler>();
|
||||
var mockLogger = new Mock<ILogger<PosixByondInstaller>>();
|
||||
var installer = new PosixByondInstaller(mockIOManager.Object, mockPostWriteHandler.Object, mockLogger.Object);
|
||||
var installer = new PosixByondInstaller(mockPostWriteHandler.Object, mockIOManager.Object, mockLogger.Object);
|
||||
|
||||
await Assert.ThrowsExceptionAsync<ArgumentNullException>(() => installer.DownloadVersion(null, default)).ConfigureAwait(false);
|
||||
|
||||
@@ -79,7 +79,7 @@ namespace Tgstation.Server.Host.Components.Byond.Tests
|
||||
var mockIOManager = new Mock<IIOManager>();
|
||||
var mockPostWriteHandler = new Mock<IPostWriteHandler>();
|
||||
var mockLogger = new Mock<ILogger<PosixByondInstaller>>();
|
||||
var installer = new PosixByondInstaller(mockIOManager.Object, mockPostWriteHandler.Object, mockLogger.Object);
|
||||
var installer = new PosixByondInstaller(mockPostWriteHandler.Object, mockIOManager.Object, mockLogger.Object);
|
||||
|
||||
const string FakePath = "fake";
|
||||
await Assert.ThrowsExceptionAsync<ArgumentNullException>(() => installer.InstallByond(null, null, default)).ConfigureAwait(false);
|
||||
|
||||
Reference in New Issue
Block a user