From e79988c2f120cdd21d5f3bd4249a6455e1854f95 Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Mon, 23 Jul 2018 15:07:40 -0400 Subject: [PATCH 01/16] Add skeleton BYOND implementation --- src/Tgstation.Server.Host/Components/Byond.cs | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 src/Tgstation.Server.Host/Components/Byond.cs diff --git a/src/Tgstation.Server.Host/Components/Byond.cs b/src/Tgstation.Server.Host/Components/Byond.cs new file mode 100644 index 0000000000..1e3e5e39df --- /dev/null +++ b/src/Tgstation.Server.Host/Components/Byond.cs @@ -0,0 +1,63 @@ +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Tgstation.Server.Host.IO; + +namespace Tgstation.Server.Host.Components +{ + /// + sealed class Byond : IByond + { + /// + /// The for + /// + readonly IIOManager ioManager; + + /// + /// The for + /// + readonly ILogger logger; + + /// + /// List of installed BYOND s + /// + readonly List installedVersions; + + /// + /// Construct + /// + /// The value of + /// The value of + public Byond(IIOManager ioManager, ILogger logger) + { + this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); + this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); + } + + /// + public Task ChangeVersion(Version version, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + /// + public Task ClearCache(CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + /// + public Task GetVersion(CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + /// + public IByondExecutableLock UseExecutables(Version requiredVersion) + { + throw new NotImplementedException(); + } + } +} From adbc02a7c1604d4f0fa0091d6ca78bbc6687646b Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Mon, 23 Jul 2018 15:09:14 -0400 Subject: [PATCH 02/16] Delete server settings. Remove soft stop. Posting an Administration API model should always reboot it --- .../Models/Administration.cs | 8 +------ .../Models/Internal/ServerSettings.cs | 23 ------------------- .../Models/DatabaseContext.cs | 15 ------------ .../Models/IDatabaseContext.cs | 7 ------ .../Models/ServerSettings.cs | 11 --------- 5 files changed, 1 insertion(+), 63 deletions(-) delete mode 100644 src/Tgstation.Server.Api/Models/Internal/ServerSettings.cs delete mode 100644 src/Tgstation.Server.Host/Models/ServerSettings.cs diff --git a/src/Tgstation.Server.Api/Models/Administration.cs b/src/Tgstation.Server.Api/Models/Administration.cs index 640a5c65ac..9e51bd7d3c 100644 --- a/src/Tgstation.Server.Api/Models/Administration.cs +++ b/src/Tgstation.Server.Api/Models/Administration.cs @@ -5,14 +5,8 @@ using Tgstation.Server.Api.Rights; namespace Tgstation.Server.Api.Models { /// - public sealed class Administration : Internal.ServerSettings + public sealed class Administration { - /// - /// If the instances will not be stopped when the server exits. Resets to when the server restarts - /// - [Permissions(ReadRight = AdministrationRights.SoftStop, WriteRight = AdministrationRights.SoftStop)] - public bool SoftStop { get; set; } - /// /// The latest available version of the Tgstation.Server.Host assembly from the upstream repository. If is higher than 's the update cannot be applied due to API changes /// diff --git a/src/Tgstation.Server.Api/Models/Internal/ServerSettings.cs b/src/Tgstation.Server.Api/Models/Internal/ServerSettings.cs deleted file mode 100644 index 3ab52adef5..0000000000 --- a/src/Tgstation.Server.Api/Models/Internal/ServerSettings.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Tgstation.Server.Api.Rights; - -namespace Tgstation.Server.Api.Models.Internal -{ - /// - /// Metadata about an installation - /// - [Model(RightsType.Administration)] - public class ServerSettings - { - /// - /// Automatically send unhandled exception data to a public collection service. This will be limited to system information, path data, and game code compilation information. - /// - [Permissions(ReadRight = AdministrationRights.ChangeTelemetry, WriteRight = AdministrationRights.ChangeTelemetry)] - public bool EnableTelemetry { get; set; } - - /// - /// The git repository URL to recieve updates to Tgstation.Server.Host from, must include credentials if necessary. If set to upstream pulls will be disabled entirely. Should be https://github.com/tgstation/tgstation-server or a fork of it - /// - [Permissions(ReadRight = AdministrationRights.SetUpstreamRepository, WriteRight = AdministrationRights.SetUpstreamRepository)] - public string UpstreamRepository { get; set; } - } -} diff --git a/src/Tgstation.Server.Host/Models/DatabaseContext.cs b/src/Tgstation.Server.Host/Models/DatabaseContext.cs index 44099444d8..c9bacb6086 100644 --- a/src/Tgstation.Server.Host/Models/DatabaseContext.cs +++ b/src/Tgstation.Server.Host/Models/DatabaseContext.cs @@ -14,9 +14,6 @@ namespace Tgstation.Server.Host.Models /// abstract class DatabaseContext : DbContext, IDatabaseContext where TParentContext : DbContext { - /// - public DbSet ServerSettings { get; set; } - /// public DbSet Users { get; set; } @@ -126,18 +123,6 @@ namespace Tgstation.Server.Host.Models base.OnConfiguring(optionsBuilder); } - /// - public async Task GetServerSettings(CancellationToken cancellationToken) - { - var settings = await ServerSettings.FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false); - if (settings == default(ServerSettings)) - { - settings = new ServerSettings(); - ServerSettings.Add(settings); - } - return settings; - } - /// public async Task Initialize(CancellationToken cancellationToken) { diff --git a/src/Tgstation.Server.Host/Models/IDatabaseContext.cs b/src/Tgstation.Server.Host/Models/IDatabaseContext.cs index 9e8d906905..0d3814a284 100644 --- a/src/Tgstation.Server.Host/Models/IDatabaseContext.cs +++ b/src/Tgstation.Server.Host/Models/IDatabaseContext.cs @@ -59,13 +59,6 @@ namespace Tgstation.Server.Host.Models /// DbSet RepositorySettings { get; set; } - /// - /// Get the in the - /// - /// The for the operation - /// A resulting in the in the - Task GetServerSettings(CancellationToken cancellationToken); - /// /// Saves changes made to the /// diff --git a/src/Tgstation.Server.Host/Models/ServerSettings.cs b/src/Tgstation.Server.Host/Models/ServerSettings.cs deleted file mode 100644 index 4326d9f563..0000000000 --- a/src/Tgstation.Server.Host/Models/ServerSettings.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Tgstation.Server.Host.Models -{ - /// - public sealed class ServerSettings : Api.Models.Internal.ServerSettings - { - /// - /// The row Id - /// - public long Id { get; set; } - } -} From 7c47cbe5656ff7ce1e1ebf3cd1e2e1af5fac0a19 Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Mon, 23 Jul 2018 15:10:18 -0400 Subject: [PATCH 03/16] Removes useless field --- src/Tgstation.Server.Api/Models/Byond.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/Tgstation.Server.Api/Models/Byond.cs b/src/Tgstation.Server.Api/Models/Byond.cs index 6654babe0a..d9a87d4643 100644 --- a/src/Tgstation.Server.Api/Models/Byond.cs +++ b/src/Tgstation.Server.Api/Models/Byond.cs @@ -20,11 +20,5 @@ namespace Tgstation.Server.Api.Models /// [Permissions(ReadRight = ByondRights.ReadInstalled, WriteRight = ByondRights.ChangeVersion)] public Version Version { get; set; } - - /// - /// The of the that's currently running the game servers - /// - [Permissions(DenyWrite = true, ReadRight = ByondRights.ReadPrevious)] - public Version PreviousVersion { get; set; } } } From 7f77d7f9ab080eb92ef72d7b4a68b4dc44773623 Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Mon, 23 Jul 2018 15:41:53 -0400 Subject: [PATCH 04/16] BYOND believable --- src/Tgstation.Server.Api/Models/Byond.cs | 6 - .../Models/ByondStatus.cs | 39 ------ src/Tgstation.Server.Host/Components/Byond.cs | 63 ---------- .../Components/ByondManager.cs | 113 ++++++++++++++++++ .../Components/DreamMaker.cs | 6 +- .../Components/IByondInstaller.cs | 30 +++++ .../{IByond.cs => IByondManager.cs} | 6 +- .../Components/IInstance.cs | 4 +- .../Components/Instance.cs | 6 +- .../Components/InstanceFactory.cs | 2 +- .../Watchdog/SessionControllerFactory.cs | 6 +- 11 files changed, 158 insertions(+), 123 deletions(-) delete mode 100644 src/Tgstation.Server.Api/Models/ByondStatus.cs delete mode 100644 src/Tgstation.Server.Host/Components/Byond.cs create mode 100644 src/Tgstation.Server.Host/Components/ByondManager.cs create mode 100644 src/Tgstation.Server.Host/Components/IByondInstaller.cs rename src/Tgstation.Server.Host/Components/{IByond.cs => IByondManager.cs} (91%) diff --git a/src/Tgstation.Server.Api/Models/Byond.cs b/src/Tgstation.Server.Api/Models/Byond.cs index d9a87d4643..b0b1647831 100644 --- a/src/Tgstation.Server.Api/Models/Byond.cs +++ b/src/Tgstation.Server.Api/Models/Byond.cs @@ -9,12 +9,6 @@ namespace Tgstation.Server.Api.Models [Model(RightsType.Byond, RequiresInstance = true)] public sealed class Byond { - /// - /// The for the installation - /// - [Permissions(DenyWrite = true, ReadRight = ByondRights.ReadStatus)] - public ByondStatus ByondStatus { get; set; } - /// /// The of the installation used for new compiles. Will be if the user does not have permission to view it or there is no BYOND version installed. Only considers the and numbers /// diff --git a/src/Tgstation.Server.Api/Models/ByondStatus.cs b/src/Tgstation.Server.Api/Models/ByondStatus.cs deleted file mode 100644 index 638a91e475..0000000000 --- a/src/Tgstation.Server.Api/Models/ByondStatus.cs +++ /dev/null @@ -1,39 +0,0 @@ -namespace Tgstation.Server.Api.Models -{ - /// - /// The status of a update job - /// -#pragma warning disable CA1717 // Only FlagsAttribute enums should have plural names - public enum ByondStatus -#pragma warning restore CA1717 // Only FlagsAttribute enums should have plural names - { - /// - /// No update in progress - /// - Idle, - /// - /// Preparing to update - /// - Starting, - /// - /// Revision is downloading - /// - Downloading, - /// - /// Revision is deflating - /// - Staging, - /// - /// Revision is ready and waiting for DreamDaemon reboot - /// - Staged, - /// - /// Revision is being applied - /// - Updating, - /// - /// User does not have permission to view the - /// - Hidden, - } -} diff --git a/src/Tgstation.Server.Host/Components/Byond.cs b/src/Tgstation.Server.Host/Components/Byond.cs deleted file mode 100644 index 1e3e5e39df..0000000000 --- a/src/Tgstation.Server.Host/Components/Byond.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Microsoft.Extensions.Logging; -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using Tgstation.Server.Host.IO; - -namespace Tgstation.Server.Host.Components -{ - /// - sealed class Byond : IByond - { - /// - /// The for - /// - readonly IIOManager ioManager; - - /// - /// The for - /// - readonly ILogger logger; - - /// - /// List of installed BYOND s - /// - readonly List installedVersions; - - /// - /// Construct - /// - /// The value of - /// The value of - public Byond(IIOManager ioManager, ILogger logger) - { - this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); - this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); - } - - /// - public Task ChangeVersion(Version version, CancellationToken cancellationToken) - { - throw new NotImplementedException(); - } - - /// - public Task ClearCache(CancellationToken cancellationToken) - { - throw new NotImplementedException(); - } - - /// - public Task GetVersion(CancellationToken cancellationToken) - { - throw new NotImplementedException(); - } - - /// - public IByondExecutableLock UseExecutables(Version requiredVersion) - { - throw new NotImplementedException(); - } - } -} diff --git a/src/Tgstation.Server.Host/Components/ByondManager.cs b/src/Tgstation.Server.Host/Components/ByondManager.cs new file mode 100644 index 0000000000..aff60de879 --- /dev/null +++ b/src/Tgstation.Server.Host/Components/ByondManager.cs @@ -0,0 +1,113 @@ +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.IO.Compression; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Tgstation.Server.Host.IO; + +namespace Tgstation.Server.Host.Components +{ + /// + sealed class ByondManager : IByondManager + { + const string VersionFileName = "Version.txt"; + + /// + /// The for the + /// + readonly IIOManager ioManager; + + /// + /// The for the + /// + readonly IByondInstaller byondInstaller; + + /// + /// The for the + /// + readonly ILogger logger; + + /// + /// Map of byond s to s that complete when they are installed + /// + readonly Dictionary installedVersions; + + /// + /// Construct a + /// + /// The value of + /// The value of + /// The value of + public ByondManager(IIOManager ioManager, IByondInstaller byondInstaller, ILogger logger) + { + this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); + this.byondInstaller = byondInstaller ?? throw new ArgumentNullException(nameof(byondInstaller)); + this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); + } + + static string VersionKey(Version version) => new Version(version.Major, version.Minor).ToString(); + + async Task InstallVersion(Version version, CancellationToken cancellationToken) + { + var ourTcs = new TaskCompletionSource(); + Task inProgressTask; + + var versionKey = VersionKey(version); + bool installed; + lock (installedVersions) + { + installed = installedVersions.TryGetValue(versionKey, out inProgressTask); + if (!installed) + installedVersions.Add(versionKey, ourTcs.Task); + } + if(installed) + using (cancellationToken.Register(() => ourTcs.SetCanceled())) + { + await Task.WhenAny(ourTcs.Task, inProgressTask).ConfigureAwait(false); + return; + } + + var downloadTask = byondInstaller.DownloadVersion(version, cancellationToken); + + //okay up to us to install it then + await ioManager.DeleteDirectory(versionKey, cancellationToken).ConfigureAwait(false); + await ioManager.CreateDirectory(versionKey, cancellationToken).ConfigureAwait(false); + + var resolvedPath = ioManager.ResolvePath(versionKey); + using (var zipBytes = await downloadTask.ConfigureAwait(false)) + using (var archive = new ZipArchive(zipBytes)) + await Task.Factory.StartNew(() => archive.ExtractToDirectory(resolvedPath), cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Current).ConfigureAwait(false); + + await byondInstaller.InstallByond(resolvedPath, cancellationToken).ConfigureAwait(false); + + //make sure to do this last because this is what tells us we have a valid version + await ioManager.WriteAllBytes(ioManager.ConcatPath(versionKey, VersionFileName), Encoding.UTF8.GetBytes(version.ToString()), cancellationToken).ConfigureAwait(false); + } + + /// + public Task ChangeVersion(Version version, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + /// + public Task ClearCache(CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + /// + public Task GetVersion(CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + /// + public IByondExecutableLock UseExecutables(Version requiredVersion) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Tgstation.Server.Host/Components/DreamMaker.cs b/src/Tgstation.Server.Host/Components/DreamMaker.cs index 06cd345bf7..58dbccfd38 100644 --- a/src/Tgstation.Server.Host/Components/DreamMaker.cs +++ b/src/Tgstation.Server.Host/Components/DreamMaker.cs @@ -39,9 +39,9 @@ namespace Tgstation.Server.Host.Components public CompilerStatus Status { get; private set; } /// - /// The for + /// The for /// - readonly IByond byond; + readonly IByondManager byond; /// /// The for /// @@ -82,7 +82,7 @@ namespace Tgstation.Server.Host.Components /// The value of /// The value of /// The value of - public DreamMaker(IByond byond, IIOManager ioManager, IConfiguration configuration, ISessionControllerFactory sessionControllerFactory, ICompileJobConsumer compileJobConsumer, IApplication application, IEventConsumer eventConsumer, ILogger logger) + public DreamMaker(IByondManager byond, IIOManager ioManager, IConfiguration configuration, ISessionControllerFactory sessionControllerFactory, ICompileJobConsumer compileJobConsumer, IApplication application, IEventConsumer eventConsumer, ILogger logger) { this.byond = byond; this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); diff --git a/src/Tgstation.Server.Host/Components/IByondInstaller.cs b/src/Tgstation.Server.Host/Components/IByondInstaller.cs new file mode 100644 index 0000000000..98a8e4831d --- /dev/null +++ b/src/Tgstation.Server.Host/Components/IByondInstaller.cs @@ -0,0 +1,30 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +using Stream = System.IO.Stream; + +namespace Tgstation.Server.Host.Components +{ + /// + /// For downloading and installing BYOND extractions + /// + interface IByondInstaller + { + /// + /// Download a given BYOND + /// + /// The of BYOND to download + /// The for the operation + /// A resulting in a of the zipfile + Task DownloadVersion(Version version, CancellationToken cancellationToken); + + /// + /// Does actions necessary to get an extracted BYOND installation working + /// + /// The path to the BYOND installation + /// The for the operation + /// + Task InstallByond(string path, CancellationToken cancellationToken); + } +} \ No newline at end of file diff --git a/src/Tgstation.Server.Host/Components/IByond.cs b/src/Tgstation.Server.Host/Components/IByondManager.cs similarity index 91% rename from src/Tgstation.Server.Host/Components/IByond.cs rename to src/Tgstation.Server.Host/Components/IByondManager.cs index 105d6dac74..a0226edd64 100644 --- a/src/Tgstation.Server.Host/Components/IByond.cs +++ b/src/Tgstation.Server.Host/Components/IByondManager.cs @@ -7,17 +7,17 @@ namespace Tgstation.Server.Host.Components /// /// For managing the BYOND installation /// - public interface IByond + public interface IByondManager { /// - /// Change the current BYOND version + /// Change the active BYOND version /// /// The new /// The for the operation Task ChangeVersion(Version version, CancellationToken cancellationToken); /// - /// Get the currently installed BYOND version + /// Get the currently active BYOND version /// /// The for the operation /// The current BYOND version diff --git a/src/Tgstation.Server.Host/Components/IInstance.cs b/src/Tgstation.Server.Host/Components/IInstance.cs index 9868430342..ffcf471681 100644 --- a/src/Tgstation.Server.Host/Components/IInstance.cs +++ b/src/Tgstation.Server.Host/Components/IInstance.cs @@ -16,9 +16,9 @@ namespace Tgstation.Server.Host.Components IRepositoryManager RepositoryManager { get; } /// - /// The for the + /// The for the /// - IByond Byond { get; } + IByondManager ByondManager { get; } /// /// The for the diff --git a/src/Tgstation.Server.Host/Components/Instance.cs b/src/Tgstation.Server.Host/Components/Instance.cs index d607053ab2..80e0a8bf3a 100644 --- a/src/Tgstation.Server.Host/Components/Instance.cs +++ b/src/Tgstation.Server.Host/Components/Instance.cs @@ -16,7 +16,7 @@ namespace Tgstation.Server.Host.Components public IRepositoryManager RepositoryManager { get; } /// - public IByond Byond { get; } + public IByondManager ByondManager { get; } /// public IDreamMaker DreamMaker { get; } @@ -59,11 +59,11 @@ namespace Tgstation.Server.Host.Components /// CancellationTokenSource timerCts; - public Instance(Api.Models.Instance metadata, IRepositoryManager repositoryManager, IByond byond, IDreamMaker dreamMaker, IWatchdog watchdog, IChat chat, IConfiguration configuration, ICompileJobConsumer compileJobConsumer, IDatabaseContextFactory databaseContextFactory, IDmbFactory dmbFactory) + public Instance(Api.Models.Instance metadata, IRepositoryManager repositoryManager, IByondManager byondManager, IDreamMaker dreamMaker, IWatchdog watchdog, IChat chat, IConfiguration configuration, ICompileJobConsumer compileJobConsumer, IDatabaseContextFactory databaseContextFactory, IDmbFactory dmbFactory) { this.metadata = metadata ?? throw new ArgumentNullException(nameof(metadata)); RepositoryManager = repositoryManager ?? throw new ArgumentNullException(nameof(repositoryManager)); - Byond = byond ?? throw new ArgumentNullException(nameof(byond)); + ByondManager = byondManager ?? throw new ArgumentNullException(nameof(byondManager)); DreamMaker = dreamMaker ?? throw new ArgumentNullException(nameof(dreamMaker)); watchdog = watchdog ?? throw new ArgumentNullException(nameof(watchdog)); Chat = chat ?? throw new ArgumentNullException(nameof(chat)); diff --git a/src/Tgstation.Server.Host/Components/InstanceFactory.cs b/src/Tgstation.Server.Host/Components/InstanceFactory.cs index 391b06d5db..ec9021ff1d 100644 --- a/src/Tgstation.Server.Host/Components/InstanceFactory.cs +++ b/src/Tgstation.Server.Host/Components/InstanceFactory.cs @@ -115,7 +115,7 @@ namespace Tgstation.Server.Host.Components var repoManager = new RepositoryManager(metadata.RepositorySettings, repoIoManager); - IByond byond = null; + IByondManager byond = null; var configuration = new Configuration(configurationIoManager, synchronousIOManager, symlinkFactory, loggerFactory.CreateLogger()); var chat = chatFactory.CreateChat(); diff --git a/src/Tgstation.Server.Host/Components/Watchdog/SessionControllerFactory.cs b/src/Tgstation.Server.Host/Components/Watchdog/SessionControllerFactory.cs index b84535a1fa..d5f6063c75 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/SessionControllerFactory.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/SessionControllerFactory.cs @@ -24,9 +24,9 @@ namespace Tgstation.Server.Host.Components.Watchdog readonly IExecutor executor; /// - /// The for the + /// The for the /// - readonly IByond byond; + readonly IByondManager byond; /// /// The for the @@ -81,7 +81,7 @@ namespace Tgstation.Server.Host.Components.Watchdog /// The value of /// The value of /// The value of - public SessionControllerFactory(IExecutor executor, IByond byond, IByondTopicSender byondTopicSender, IInteropRegistrar interopRegistrar, ICryptographySuite cryptographySuite, IApplication application, IIOManager ioManager, IChat chat, ILoggerFactory loggerFactory, Models.Instance instance) + public SessionControllerFactory(IExecutor executor, IByondManager byond, IByondTopicSender byondTopicSender, IInteropRegistrar interopRegistrar, ICryptographySuite cryptographySuite, IApplication application, IIOManager ioManager, IChat chat, ILoggerFactory loggerFactory, Models.Instance instance) { this.executor = executor ?? throw new ArgumentNullException(nameof(executor)); this.byond = byond ?? throw new ArgumentNullException(nameof(byond)); From 902333674459de5c22d99fbc7444ecbfdfce8dd0 Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Mon, 23 Jul 2018 16:14:04 -0400 Subject: [PATCH 05/16] More ByondManager stuff --- .../Components/ByondExecutableLock.cs | 17 +++++ .../Components/ByondManager.cs | 69 ++++++++++++++++--- .../Components/IByondInstaller.cs | 19 ++++- .../Components/IByondManager.cs | 26 +++---- 4 files changed, 104 insertions(+), 27 deletions(-) create mode 100644 src/Tgstation.Server.Host/Components/ByondExecutableLock.cs diff --git a/src/Tgstation.Server.Host/Components/ByondExecutableLock.cs b/src/Tgstation.Server.Host/Components/ByondExecutableLock.cs new file mode 100644 index 0000000000..2e89dacb38 --- /dev/null +++ b/src/Tgstation.Server.Host/Components/ByondExecutableLock.cs @@ -0,0 +1,17 @@ +using System; + +namespace Tgstation.Server.Host.Components +{ + sealed class ByondExecutableLock : IByondExecutableLock + { + public Version Version { get; set; } + + public string DreamDaemonPath { get; set; } + + public string DreamMakerPath { get; set; } + + public void Dispose() { } + + public void DoNotDeleteThisSession() { } + } +} diff --git a/src/Tgstation.Server.Host/Components/ByondManager.cs b/src/Tgstation.Server.Host/Components/ByondManager.cs index aff60de879..1c00689b34 100644 --- a/src/Tgstation.Server.Host/Components/ByondManager.cs +++ b/src/Tgstation.Server.Host/Components/ByondManager.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.IO.Compression; +using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -13,6 +14,12 @@ namespace Tgstation.Server.Host.Components sealed class ByondManager : IByondManager { const string VersionFileName = "Version.txt"; + const string ActiveVersionFileName = "ActiveVersion.txt"; + + const string BinPath = "byond/bin"; + + /// + public Version ActiveVersion { get; private set; } /// /// The for the @@ -87,27 +94,69 @@ namespace Tgstation.Server.Host.Components } /// - public Task ChangeVersion(Version version, CancellationToken cancellationToken) + public async Task ChangeVersion(Version version, CancellationToken cancellationToken) { - throw new NotImplementedException(); + await InstallVersion(version, cancellationToken).ConfigureAwait(false); + await ioManager.WriteAllBytes(ActiveVersionFileName, Encoding.UTF8.GetBytes(version.ToString()), cancellationToken).ConfigureAwait(false); + ActiveVersion = version; } /// - public Task ClearCache(CancellationToken cancellationToken) + public async Task UseExecutables(Version requiredVersion, CancellationToken cancellationToken) { - throw new NotImplementedException(); + var versionToUse = requiredVersion ?? ActiveVersion; + if (versionToUse == null) + throw new InvalidOperationException("No BYOND versions installed!"); + await InstallVersion(requiredVersion, cancellationToken).ConfigureAwait(false); + + var versionKey = VersionKey(versionToUse); + + return new ByondExecutableLock + { + DreamDaemonPath = ioManager.ResolvePath(ioManager.ConcatPath(versionKey, byondInstaller.DreamDaemonName)), + DreamMakerPath = ioManager.ResolvePath(ioManager.ConcatPath(versionKey, byondInstaller.DreamMakerName)), + Version = versionToUse + }; } /// - public Task GetVersion(CancellationToken cancellationToken) + public async Task StartAsync(CancellationToken cancellationToken) { - throw new NotImplementedException(); + var cacheCleanTask = byondInstaller.CleanCache(cancellationToken); + + var activeVersionBytesTask = ioManager.ReadAllBytes(ActiveVersionFileName, cancellationToken); + + var directories = await ioManager.GetDirectories(".", cancellationToken).ConfigureAwait(false); + + async Task ReadVersion(string path) + { + var bytes = await ioManager.ReadAllBytes(ioManager.ConcatPath(path, VersionFileName), cancellationToken).ConfigureAwait(false); + var text = Encoding.UTF8.GetString(bytes); + if (Version.TryParse(text, out var version)) + { + var key = VersionKey(version); + lock (installedVersions) + if (!installedVersions.ContainsKey(key)) + { + installedVersions.Add(key, Task.CompletedTask); + return; + } + } + await ioManager.DeleteDirectory(path, cancellationToken).ConfigureAwait(false); + }; + + await Task.WhenAll(directories.Select(x => ReadVersion(x))).ConfigureAwait(false); + + var activeVersionString = Encoding.UTF8.GetString(await activeVersionBytesTask.ConfigureAwait(false)); + if (Version.TryParse(activeVersionString, out var activeVersion)) + ActiveVersion = activeVersion; + else + await ioManager.DeleteFile(ActiveVersionFileName, cancellationToken).ConfigureAwait(false); + + await cacheCleanTask.ConfigureAwait(false); } /// - public IByondExecutableLock UseExecutables(Version requiredVersion) - { - throw new NotImplementedException(); - } + public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; } } diff --git a/src/Tgstation.Server.Host/Components/IByondInstaller.cs b/src/Tgstation.Server.Host/Components/IByondInstaller.cs index 98a8e4831d..2779e19969 100644 --- a/src/Tgstation.Server.Host/Components/IByondInstaller.cs +++ b/src/Tgstation.Server.Host/Components/IByondInstaller.cs @@ -7,10 +7,20 @@ using Stream = System.IO.Stream; namespace Tgstation.Server.Host.Components { /// - /// For downloading and installing BYOND extractions + /// For downloading and installing BYOND extractions for a given system /// interface IByondInstaller { + /// + /// Get the file name of the DreamDaemon executable + /// + string DreamDaemonName { get; } + + /// + /// Get the file name of the DreamMaker executable + /// + string DreamMakerName { get; } + /// /// Download a given BYOND /// @@ -26,5 +36,12 @@ namespace Tgstation.Server.Host.Components /// The for the operation /// Task InstallByond(string path, CancellationToken cancellationToken); + + /// + /// Attempts to cleans the BYOND cache folder for the system + /// + /// The for the operation + /// A representing the running operation + Task CleanCache(CancellationToken cancellationToken); } } \ No newline at end of file diff --git a/src/Tgstation.Server.Host/Components/IByondManager.cs b/src/Tgstation.Server.Host/Components/IByondManager.cs index a0226edd64..c6ac12119e 100644 --- a/src/Tgstation.Server.Host/Components/IByondManager.cs +++ b/src/Tgstation.Server.Host/Components/IByondManager.cs @@ -1,4 +1,5 @@ -using System; +using Microsoft.Extensions.Hosting; +using System; using System.Threading; using System.Threading.Tasks; @@ -7,8 +8,13 @@ namespace Tgstation.Server.Host.Components /// /// For managing the BYOND installation /// - public interface IByondManager + public interface IByondManager : IHostedService { + /// + /// The currently active BYOND version + /// + Version ActiveVersion { get; } + /// /// Change the active BYOND version /// @@ -16,24 +22,12 @@ namespace Tgstation.Server.Host.Components /// The for the operation Task ChangeVersion(Version version, CancellationToken cancellationToken); - /// - /// Get the currently active BYOND version - /// - /// The for the operation - /// The current BYOND version - Task GetVersion(CancellationToken cancellationToken); - /// /// Lock the current installation's location and return a /// /// The BYOND required - IByondExecutableLock UseExecutables(Version requiredVersion); - - /// - /// Clears the cache folder - /// /// The for the operation - /// A representing the running operation - Task ClearCache(CancellationToken cancellationToken); + /// A resulting in the requested + Task UseExecutables(Version requiredVersion, CancellationToken cancellationToken); } } \ No newline at end of file From e98dde5089c5a8a05c8269b143eb13d7b0fc55d0 Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Mon, 23 Jul 2018 16:15:48 -0400 Subject: [PATCH 06/16] Docs for ByondExecutableLock --- .../Components/ByondExecutableLock.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Tgstation.Server.Host/Components/ByondExecutableLock.cs b/src/Tgstation.Server.Host/Components/ByondExecutableLock.cs index 2e89dacb38..2be7ab498a 100644 --- a/src/Tgstation.Server.Host/Components/ByondExecutableLock.cs +++ b/src/Tgstation.Server.Host/Components/ByondExecutableLock.cs @@ -2,16 +2,25 @@ namespace Tgstation.Server.Host.Components { + /// sealed class ByondExecutableLock : IByondExecutableLock { + /// public Version Version { get; set; } + /// public string DreamDaemonPath { get; set; } + /// public string DreamMakerPath { get; set; } + //at one point in design, byond versions were to delete themselves if they werent the active version + //That changed at some point so these functions are intentioanlly left blank + + /// public void Dispose() { } + /// public void DoNotDeleteThisSession() { } } } From a56c8b20f9a689b33bbcd287651f38a09bb34d1b Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Mon, 23 Jul 2018 16:32:34 -0400 Subject: [PATCH 07/16] WindowsByondInstaller stuff --- .../Components/ByondManager.cs | 4 +- .../Components/IByondInstaller.cs | 6 +-- .../Components/WindowsByondInstaller.cs | 47 +++++++++++++++++++ .../IO/DefaultIOManager.cs | 9 ++++ src/Tgstation.Server.Host/IO/IIOManager.cs | 11 ++++- 5 files changed, 71 insertions(+), 6 deletions(-) create mode 100644 src/Tgstation.Server.Host/Components/WindowsByondInstaller.cs diff --git a/src/Tgstation.Server.Host/Components/ByondManager.cs b/src/Tgstation.Server.Host/Components/ByondManager.cs index 1c00689b34..9613157065 100644 --- a/src/Tgstation.Server.Host/Components/ByondManager.cs +++ b/src/Tgstation.Server.Host/Components/ByondManager.cs @@ -8,6 +8,8 @@ using System.Threading; using System.Threading.Tasks; using Tgstation.Server.Host.IO; +using MemoryStream = System.IO.MemoryStream; + namespace Tgstation.Server.Host.Components { /// @@ -83,7 +85,7 @@ namespace Tgstation.Server.Host.Components await ioManager.CreateDirectory(versionKey, cancellationToken).ConfigureAwait(false); var resolvedPath = ioManager.ResolvePath(versionKey); - using (var zipBytes = await downloadTask.ConfigureAwait(false)) + using (var zipBytes = new MemoryStream(await downloadTask.ConfigureAwait(false))) using (var archive = new ZipArchive(zipBytes)) await Task.Factory.StartNew(() => archive.ExtractToDirectory(resolvedPath), cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Current).ConfigureAwait(false); diff --git a/src/Tgstation.Server.Host/Components/IByondInstaller.cs b/src/Tgstation.Server.Host/Components/IByondInstaller.cs index 2779e19969..4b3b6996d3 100644 --- a/src/Tgstation.Server.Host/Components/IByondInstaller.cs +++ b/src/Tgstation.Server.Host/Components/IByondInstaller.cs @@ -2,8 +2,6 @@ using System.Threading; using System.Threading.Tasks; -using Stream = System.IO.Stream; - namespace Tgstation.Server.Host.Components { /// @@ -26,8 +24,8 @@ namespace Tgstation.Server.Host.Components /// /// The of BYOND to download /// The for the operation - /// A resulting in a of the zipfile - Task DownloadVersion(Version version, CancellationToken cancellationToken); + /// A resulting in the s of the zipfile + Task DownloadVersion(Version version, CancellationToken cancellationToken); /// /// Does actions necessary to get an extracted BYOND installation working diff --git a/src/Tgstation.Server.Host/Components/WindowsByondInstaller.cs b/src/Tgstation.Server.Host/Components/WindowsByondInstaller.cs new file mode 100644 index 0000000000..de1637fd34 --- /dev/null +++ b/src/Tgstation.Server.Host/Components/WindowsByondInstaller.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Tgstation.Server.Host.IO; + +namespace Tgstation.Server.Host.Components +{ + /// + /// for windows systems + /// + sealed class WindowsByondInstaller : IByondInstaller + { + /// + /// The URL format string for getting BYOND windows version {0}.{1} zipfile + /// + const string ByondRevisionsURL = "https://secure.byond.com/download/build/{0}/{0}.{1}_byond.zip"; + + /// + public string DreamDaemonName => "dreamdaemon.exe"; + + /// + public string DreamMakerName => "dm.exe"; + + /// + /// The for the + /// + readonly IIOManager ioManager; + + public Task CleanCache(CancellationToken cancellationToken) => ioManager.DeleteDirectory(ioManager.ConcatPath(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "byond/cache"), cancellationToken); + + public Task DownloadVersion(Version version, CancellationToken cancellationToken) + { + var url = String.Format(CultureInfo.InvariantCulture, ByondRevisionsURL, version.Major, version.Major); + + return ioManager.DownloadFile(new Uri(url), cancellationToken); + } + + public Task InstallByond(string path, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Tgstation.Server.Host/IO/DefaultIOManager.cs b/src/Tgstation.Server.Host/IO/DefaultIOManager.cs index 5a4bb9654f..793b5881e2 100644 --- a/src/Tgstation.Server.Host/IO/DefaultIOManager.cs +++ b/src/Tgstation.Server.Host/IO/DefaultIOManager.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; +using System.Net; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -243,5 +244,13 @@ namespace Tgstation.Server.Host.IO link = ResolvePath(link); }, cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Current); + + /// + public async Task DownloadFile(Uri url, CancellationToken cancellationToken) + { + using (var wc = new WebClient()) + using (cancellationToken.Register(() => wc.CancelAsync())) + return await wc.DownloadDataTaskAsync(url).ConfigureAwait(false); + } } } diff --git a/src/Tgstation.Server.Host/IO/IIOManager.cs b/src/Tgstation.Server.Host/IO/IIOManager.cs index e5b6cdefde..ad320805d3 100644 --- a/src/Tgstation.Server.Host/IO/IIOManager.cs +++ b/src/Tgstation.Server.Host/IO/IIOManager.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; @@ -153,5 +154,13 @@ namespace Tgstation.Server.Host.IO /// A for the operation /// A representing the running operation Task MoveFile(string source, string destination, CancellationToken cancellationToken); + + /// + /// Downloads a file from + /// + /// The URL to download + /// A for the operation + /// A resulting in the s of the downloaded file + Task DownloadFile(Uri url, CancellationToken cancellationToken); } } From 2b1e65a496427fc171b56b58d27115a2652c96b9 Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Mon, 23 Jul 2018 16:45:18 -0400 Subject: [PATCH 08/16] Finish writing WindowsByondInstaller --- .../Components/ByondManager.cs | 2 +- .../Components/IByondInstaller.cs | 3 +- .../Components/WindowsByondInstaller.cs | 86 ++++++++++++++++++- src/Tgstation.Server.Host/Core/Application.cs | 1 + 4 files changed, 86 insertions(+), 6 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/ByondManager.cs b/src/Tgstation.Server.Host/Components/ByondManager.cs index 9613157065..67e1c3f110 100644 --- a/src/Tgstation.Server.Host/Components/ByondManager.cs +++ b/src/Tgstation.Server.Host/Components/ByondManager.cs @@ -89,7 +89,7 @@ namespace Tgstation.Server.Host.Components using (var archive = new ZipArchive(zipBytes)) await Task.Factory.StartNew(() => archive.ExtractToDirectory(resolvedPath), cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Current).ConfigureAwait(false); - await byondInstaller.InstallByond(resolvedPath, cancellationToken).ConfigureAwait(false); + await byondInstaller.InstallByond(resolvedPath, version, cancellationToken).ConfigureAwait(false); //make sure to do this last because this is what tells us we have a valid version await ioManager.WriteAllBytes(ioManager.ConcatPath(versionKey, VersionFileName), Encoding.UTF8.GetBytes(version.ToString()), cancellationToken).ConfigureAwait(false); diff --git a/src/Tgstation.Server.Host/Components/IByondInstaller.cs b/src/Tgstation.Server.Host/Components/IByondInstaller.cs index 4b3b6996d3..9ad7e26510 100644 --- a/src/Tgstation.Server.Host/Components/IByondInstaller.cs +++ b/src/Tgstation.Server.Host/Components/IByondInstaller.cs @@ -31,9 +31,10 @@ namespace Tgstation.Server.Host.Components /// Does actions necessary to get an extracted BYOND installation working /// /// The path to the BYOND installation + /// The of BYOND being installed /// The for the operation /// - Task InstallByond(string path, CancellationToken cancellationToken); + Task InstallByond(string path, Version version, CancellationToken cancellationToken); /// /// Attempts to cleans the BYOND cache folder for the system diff --git a/src/Tgstation.Server.Host/Components/WindowsByondInstaller.cs b/src/Tgstation.Server.Host/Components/WindowsByondInstaller.cs index de1637fd34..1a5274eae4 100644 --- a/src/Tgstation.Server.Host/Components/WindowsByondInstaller.cs +++ b/src/Tgstation.Server.Host/Components/WindowsByondInstaller.cs @@ -1,7 +1,6 @@ using System; -using System.Collections.Generic; +using System.Diagnostics; using System.Globalization; -using System.IO; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -18,6 +17,18 @@ namespace Tgstation.Server.Host.Components /// The URL format string for getting BYOND windows version {0}.{1} zipfile /// const string ByondRevisionsURL = "https://secure.byond.com/download/build/{0}/{0}.{1}_byond.zip"; + /// + /// BYOND's DreamDaemon config file in the cfg modification directory + /// + const string ByondDDConfig = "byond/config/daemon.txt"; + /// + /// Setting to add to to suppress an invisible user prompt for running a trusted mode .dmb + /// + const string ByondNoPromptTrustedMode = "trusted-check 0"; + /// + /// The directory that contains the BYOND directx redistributable + /// + const string ByondDXDir = "byond/directx"; /// public string DreamDaemonName => "dreamdaemon.exe"; @@ -30,8 +41,26 @@ namespace Tgstation.Server.Host.Components /// readonly IIOManager ioManager; + /// + /// If DirectX was installed + /// + bool installedDirectX; + + /// + /// Construct a + /// + /// The value of + public WindowsByondInstaller(IIOManager ioManager) + { + this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); + + installedDirectX = false; + } + + /// public Task CleanCache(CancellationToken cancellationToken) => ioManager.DeleteDirectory(ioManager.ConcatPath(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "byond/cache"), cancellationToken); + /// public Task DownloadVersion(Version version, CancellationToken cancellationToken) { var url = String.Format(CultureInfo.InvariantCulture, ByondRevisionsURL, version.Major, version.Major); @@ -39,9 +68,58 @@ namespace Tgstation.Server.Host.Components return ioManager.DownloadFile(new Uri(url), cancellationToken); } - public Task InstallByond(string path, CancellationToken cancellationToken) + /// + public async Task InstallByond(string path, Version version, CancellationToken cancellationToken) { - throw new NotImplementedException(); + var setNoPromptTrustedModeTask = ioManager.WriteAllBytes(ByondDDConfig, Encoding.UTF8.GetBytes(ByondNoPromptTrustedMode), cancellationToken); + + //after this version lummox made DD depend of directx lol + if (version.Major >= 512 && version.Minor >= 1427 && Monitor.TryEnter(this)) + try + { + if (!installedDirectX) + //always install it, it's pretty fast and will do better redundancy checking than us + using (var p = new Process()) + { + p.StartInfo.Arguments = "/silent"; + var rbdx = ioManager.ConcatPath(path, ByondDXDir); + p.StartInfo.FileName = rbdx + "/DXSETUP.exe"; + p.StartInfo.UseShellExecute = false; + p.StartInfo.WorkingDirectory = rbdx; + p.EnableRaisingEvents = true; + var tcs = new TaskCompletionSource(); + p.Exited += (a, b) => tcs.SetResult(null); + try + { + p.Start(); + using (cancellationToken.Register(() => + { + p.Kill(); + tcs.SetCanceled(); + })) + await tcs.Task.ConfigureAwait(false); + } + finally + { + try + { + p.Kill(); + p.WaitForExit(); + } + catch (InvalidOperationException) { } + } + + if (p.ExitCode != 0) + throw new Exception("Failed to install included DirectX! Exit code: " + p.ExitCode); + installedDirectX = true; + } + } + finally + { + Monitor.Exit(this); + } + + await setNoPromptTrustedModeTask.ConfigureAwait(false); } } } diff --git a/src/Tgstation.Server.Host/Core/Application.cs b/src/Tgstation.Server.Host/Core/Application.cs index ab686c1495..35cde358b6 100644 --- a/src/Tgstation.Server.Host/Core/Application.cs +++ b/src/Tgstation.Server.Host/Core/Application.cs @@ -154,6 +154,7 @@ namespace Tgstation.Server.Host.Core { services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); } else { From 39680073858ba6faed9702aa79aa19fe395f8d26 Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Mon, 23 Jul 2018 17:01:52 -0400 Subject: [PATCH 09/16] Implement PosixByondInstaller --- .../Components/PosixByondInstaller.cs | 93 +++++++++++++++++++ .../Components/WindowsByondInstaller.cs | 26 +++++- src/Tgstation.Server.Host/Core/Application.cs | 1 + 3 files changed, 116 insertions(+), 4 deletions(-) create mode 100644 src/Tgstation.Server.Host/Components/PosixByondInstaller.cs diff --git a/src/Tgstation.Server.Host/Components/PosixByondInstaller.cs b/src/Tgstation.Server.Host/Components/PosixByondInstaller.cs new file mode 100644 index 0000000000..2a3e5cd44d --- /dev/null +++ b/src/Tgstation.Server.Host/Components/PosixByondInstaller.cs @@ -0,0 +1,93 @@ +using Microsoft.Extensions.Logging; +using System; +using System.Globalization; +using System.Net; +using System.Threading; +using System.Threading.Tasks; +using Tgstation.Server.Host.IO; + +namespace Tgstation.Server.Host.Components +{ + /// + /// for Posix systems + /// + sealed class PosixByondInstaller : IByondInstaller + { + /// + /// The URL format string for getting BYOND linux version {0}.{1} zipfile + /// + const string ByondRevisionsURL = "https://secure.byond.com/download/build/{0}/{0}.{1}_byond_linux.zip"; + /// + /// Path to the BYOND cache + /// + const string ByondCachePath = "~/.byond"; //TODO: Verify this is correct!!!!! + + /// + public string DreamDaemonName => "DreamDaemon"; + + /// + public string DreamMakerName => "DreamMaker"; + + /// + /// The for the + /// + readonly IIOManager ioManager; + + /// + /// The for the + /// + readonly ILogger logger; + + /// + /// Construct a + /// + /// The value of + /// The value of + public PosixByondInstaller(IIOManager ioManager, ILogger logger) + { + this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); + this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); + } + + /// + public async Task CleanCache(CancellationToken cancellationToken) + { + try + { + await ioManager.DeleteDirectory(ByondCachePath, cancellationToken).ConfigureAwait(false); + } + catch (Exception e) + { + logger.LogWarning("Error deleting BYOND cache! Exception: {0}", e); + } + } + + /// + public async Task DownloadVersion(Version version, CancellationToken cancellationToken) + { + var ourVersion = version; + //lummox is annoying and doesn't like to post linux versions if nothing changed in DreamDaemon/DM + //if this for's exit condition ever triggers, i get to say I told you so + Exception lastException = null; + for (var I = 0; I < 5 && ourVersion.Minor >= 1; ++I, ourVersion = new Version(ourVersion.Major, ourVersion.Minor)) + { + try + { + var url = String.Format(CultureInfo.InvariantCulture, ByondRevisionsURL, ourVersion.Major, ourVersion.Minor); + + return await ioManager.DownloadFile(new Uri(url), cancellationToken).ConfigureAwait(false); + } + catch (WebException e) + { + if (!(e.Status == WebExceptionStatus.ProtocolError && e.Response is HttpWebResponse response && response.StatusCode == HttpStatusCode.NotFound)) + throw; + lastException = e; + } + } + throw lastException; + } + + /// + public Task InstallByond(string path, Version version, CancellationToken cancellationToken) => Task.CompletedTask; + } +} diff --git a/src/Tgstation.Server.Host/Components/WindowsByondInstaller.cs b/src/Tgstation.Server.Host/Components/WindowsByondInstaller.cs index 1a5274eae4..6b102ace09 100644 --- a/src/Tgstation.Server.Host/Components/WindowsByondInstaller.cs +++ b/src/Tgstation.Server.Host/Components/WindowsByondInstaller.cs @@ -1,4 +1,5 @@ -using System; +using Microsoft.Extensions.Logging; +using System; using System.Diagnostics; using System.Globalization; using System.Text; @@ -41,6 +42,11 @@ namespace Tgstation.Server.Host.Components /// readonly IIOManager ioManager; + /// + /// The for the + /// + readonly ILogger logger; + /// /// If DirectX was installed /// @@ -50,20 +56,32 @@ namespace Tgstation.Server.Host.Components /// Construct a /// /// The value of - public WindowsByondInstaller(IIOManager ioManager) + /// The value of + public WindowsByondInstaller(IIOManager ioManager, ILogger logger) { this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); + this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); installedDirectX = false; } /// - public Task CleanCache(CancellationToken cancellationToken) => ioManager.DeleteDirectory(ioManager.ConcatPath(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "byond/cache"), cancellationToken); + public async Task CleanCache(CancellationToken cancellationToken) + { + try + { + await ioManager.DeleteDirectory(ioManager.ConcatPath(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "byond/cache"), cancellationToken).ConfigureAwait(false); + } + catch (Exception e) + { + logger.LogWarning("Error deleting BYOND cache! Exception: {0}", e); + } + } /// public Task DownloadVersion(Version version, CancellationToken cancellationToken) { - var url = String.Format(CultureInfo.InvariantCulture, ByondRevisionsURL, version.Major, version.Major); + var url = String.Format(CultureInfo.InvariantCulture, ByondRevisionsURL, version.Major, version.Minor); return ioManager.DownloadFile(new Uri(url), cancellationToken); } diff --git a/src/Tgstation.Server.Host/Core/Application.cs b/src/Tgstation.Server.Host/Core/Application.cs index 35cde358b6..aee2ab7feb 100644 --- a/src/Tgstation.Server.Host/Core/Application.cs +++ b/src/Tgstation.Server.Host/Core/Application.cs @@ -160,6 +160,7 @@ namespace Tgstation.Server.Host.Core { services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); } services.AddSingleton(); From 6425e8c37e2dd98484e1eb3b559db7221d9ca1ae Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Mon, 23 Jul 2018 21:46:38 -0400 Subject: [PATCH 10/16] Fix build errors --- src/Tgstation.Server.Host/Components/DreamMaker.cs | 2 +- .../Components/Watchdog/SessionControllerFactory.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/DreamMaker.cs b/src/Tgstation.Server.Host/Components/DreamMaker.cs index 58dbccfd38..7d1c19ba36 100644 --- a/src/Tgstation.Server.Host/Components/DreamMaker.cs +++ b/src/Tgstation.Server.Host/Components/DreamMaker.cs @@ -274,7 +274,7 @@ namespace Tgstation.Server.Host.Components //run compiler, verify api bool ddVerified; - using (var byondLock = byond.UseExecutables(null)) + using (var byondLock = await byond.UseExecutables(null, cancellationToken).ConfigureAwait(false)) { job.ByondVersion = byondLock.Version.ToString(); diff --git a/src/Tgstation.Server.Host/Components/Watchdog/SessionControllerFactory.cs b/src/Tgstation.Server.Host/Components/Watchdog/SessionControllerFactory.cs index d5f6063c75..9b48f51f8d 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/SessionControllerFactory.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/SessionControllerFactory.cs @@ -142,7 +142,7 @@ namespace Tgstation.Server.Host.Components.Watchdog var chatJsonTrackingContext = await chatJsonTrackingTask.ConfigureAwait(false); try { - var byondLock = currentByondLock ?? byond.UseExecutables(Version.Parse(dmbProvider.CompileJob.ByondVersion)); + var byondLock = currentByondLock ?? await byond.UseExecutables(Version.Parse(dmbProvider.CompileJob.ByondVersion), cancellationToken).ConfigureAwait(false); try { //more sanitization here cause it uses the same scheme @@ -190,7 +190,7 @@ namespace Tgstation.Server.Host.Components.Watchdog var chatJsonTrackingContext = await chat.TrackJsons(basePath, reattachInformation.ChatChannelsJson, reattachInformation.ChatCommandsJson, cancellationToken).ConfigureAwait(false); try { - var byondLock = byond.UseExecutables(Version.Parse(reattachInformation.Dmb.CompileJob.ByondVersion)); + var byondLock = await byond.UseExecutables(Version.Parse(reattachInformation.Dmb.CompileJob.ByondVersion), cancellationToken).ConfigureAwait(false); try { var session = executor.AttachToDreamDaemon(reattachInformation.ProcessId, byondLock); From e76061ae59e648af82cd683a603851b4118e2ae8 Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Mon, 23 Jul 2018 22:24:53 -0400 Subject: [PATCH 11/16] Actually fix the build --- src/Tgstation.Server.Host/Models/DatabaseSeeder.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/Tgstation.Server.Host/Models/DatabaseSeeder.cs b/src/Tgstation.Server.Host/Models/DatabaseSeeder.cs index 772368aed3..37bf2f1c0f 100644 --- a/src/Tgstation.Server.Host/Models/DatabaseSeeder.cs +++ b/src/Tgstation.Server.Host/Models/DatabaseSeeder.cs @@ -60,12 +60,6 @@ namespace Tgstation.Server.Host.Models public async Task SeedDatabase(IDatabaseContext databaseContext, CancellationToken cancellationToken) { SeedAdminUser(databaseContext); - - var serverSettings = await databaseContext.GetServerSettings(cancellationToken).ConfigureAwait(false); - - serverSettings.EnableTelemetry = true; - serverSettings.UpstreamRepository = DefaultUpstreamRepository; - await databaseContext.Save(cancellationToken).ConfigureAwait(false); } From 6aa35d25430a0c6fba7ac7880d25deab33104c93 Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Mon, 23 Jul 2018 22:40:01 -0400 Subject: [PATCH 12/16] Actually actually fix the build --- src/Tgstation.Server.Client/Components/IByondClient.cs | 5 ++--- src/Tgstation.Server.Host/Components/ByondManager.cs | 2 ++ src/Tgstation.Server.Host/Components/Instance.cs | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Tgstation.Server.Client/Components/IByondClient.cs b/src/Tgstation.Server.Client/Components/IByondClient.cs index f7e064e0b2..403f6dd34a 100644 --- a/src/Tgstation.Server.Client/Components/IByondClient.cs +++ b/src/Tgstation.Server.Client/Components/IByondClient.cs @@ -21,10 +21,9 @@ namespace Tgstation.Server.Client.Components /// /// Updates the installed BYOND /// - /// The to update - /// Optional taking a to run when it changes + /// The to set to active /// The for the operation /// A representing the running operation - Task Update(Byond byond, Action progressCallback, CancellationToken cancellationToken); + Task SetActiveVersion(Version version, CancellationToken cancellationToken); } } diff --git a/src/Tgstation.Server.Host/Components/ByondManager.cs b/src/Tgstation.Server.Host/Components/ByondManager.cs index 67e1c3f110..51eed66c52 100644 --- a/src/Tgstation.Server.Host/Components/ByondManager.cs +++ b/src/Tgstation.Server.Host/Components/ByondManager.cs @@ -54,6 +54,8 @@ namespace Tgstation.Server.Host.Components this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); this.byondInstaller = byondInstaller ?? throw new ArgumentNullException(nameof(byondInstaller)); this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); + + installedVersions = new Dictionary(); } static string VersionKey(Version version) => new Version(version.Major, version.Minor).ToString(); diff --git a/src/Tgstation.Server.Host/Components/Instance.cs b/src/Tgstation.Server.Host/Components/Instance.cs index 80e0a8bf3a..fea1f1b57f 100644 --- a/src/Tgstation.Server.Host/Components/Instance.cs +++ b/src/Tgstation.Server.Host/Components/Instance.cs @@ -125,10 +125,10 @@ namespace Tgstation.Server.Host.Components } /// - public Task StartAsync(CancellationToken cancellationToken) => Task.WhenAll(SetAutoUpdateInterval(metadata.AutoUpdateInterval), Watchdog.StartAsync(cancellationToken), Chat.StartAsync(cancellationToken), compileJobConsumer.StartAsync(cancellationToken), Watchdog.StartAsync(cancellationToken)); + public Task StartAsync(CancellationToken cancellationToken) => Task.WhenAll(SetAutoUpdateInterval(metadata.AutoUpdateInterval), ByondManager.StartAsync(cancellationToken), Watchdog.StartAsync(cancellationToken), Chat.StartAsync(cancellationToken), compileJobConsumer.StartAsync(cancellationToken), Watchdog.StartAsync(cancellationToken)); /// - public Task StopAsync(CancellationToken cancellationToken) => Task.WhenAll(SetAutoUpdateInterval(null), Watchdog.StopAsync(cancellationToken), Chat.StopAsync(cancellationToken), compileJobConsumer.StopAsync(cancellationToken), Watchdog.StopAsync(cancellationToken)); + public Task StopAsync(CancellationToken cancellationToken) => Task.WhenAll(SetAutoUpdateInterval(null), ByondManager.StopAsync(cancellationToken), Watchdog.StopAsync(cancellationToken), Chat.StopAsync(cancellationToken), compileJobConsumer.StopAsync(cancellationToken), Watchdog.StopAsync(cancellationToken)); /// public async Task SetAutoUpdateInterval(int? newInterval) From 27de23a4b221f8b4f93ca86b24a3945129426478 Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Mon, 23 Jul 2018 22:57:11 -0400 Subject: [PATCH 13/16] How hard is it to actually run a release build, man? --- src/Tgstation.Server.Api/Models/Byond.cs | 2 +- .../Rights/AdministrationRights.cs | 16 ++++------------ src/Tgstation.Server.Api/Rights/ByondRights.cs | 18 +++--------------- .../Components/IByondClient.cs | 2 +- .../Components/ByondManager.cs | 4 ++-- .../IO/SynchronousIOManager.cs | 18 +++++++++++------- .../Models/DatabaseSeeder.cs | 5 ----- .../Security/TestAuthenticationContext.cs | 2 +- 8 files changed, 23 insertions(+), 44 deletions(-) diff --git a/src/Tgstation.Server.Api/Models/Byond.cs b/src/Tgstation.Server.Api/Models/Byond.cs index b0b1647831..17f5b1456c 100644 --- a/src/Tgstation.Server.Api/Models/Byond.cs +++ b/src/Tgstation.Server.Api/Models/Byond.cs @@ -12,7 +12,7 @@ namespace Tgstation.Server.Api.Models /// /// The of the installation used for new compiles. Will be if the user does not have permission to view it or there is no BYOND version installed. Only considers the and numbers /// - [Permissions(ReadRight = ByondRights.ReadInstalled, WriteRight = ByondRights.ChangeVersion)] + [Permissions(ReadRight = ByondRights.ReadActive, WriteRight = ByondRights.ChangeVersion)] public Version Version { get; set; } } } diff --git a/src/Tgstation.Server.Api/Rights/AdministrationRights.cs b/src/Tgstation.Server.Api/Rights/AdministrationRights.cs index c8992b3575..58f208711c 100644 --- a/src/Tgstation.Server.Api/Rights/AdministrationRights.cs +++ b/src/Tgstation.Server.Api/Rights/AdministrationRights.cs @@ -13,24 +13,16 @@ namespace Tgstation.Server.Api.Rights /// None = 0, /// - /// User can change - /// - SetUpstreamRepository = 1, - /// - /// User can change - /// - ChangeTelemetry = 2, - /// /// User can edit themself and other s /// - EditUsers = 4, + EditUsers = 1, /// - /// User can change + /// User can gracefully restart the host /// - SoftStop = 8, + SoftStop = 2, /// /// User can change /// - ChangeVersion = 16 + ChangeVersion = 4 } } diff --git a/src/Tgstation.Server.Api/Rights/ByondRights.cs b/src/Tgstation.Server.Api/Rights/ByondRights.cs index 142ea098b4..ae650b69af 100644 --- a/src/Tgstation.Server.Api/Rights/ByondRights.cs +++ b/src/Tgstation.Server.Api/Rights/ByondRights.cs @@ -13,24 +13,12 @@ namespace Tgstation.Server.Api.Rights /// None = 0, /// - /// User may check the installed BYOND version + /// User may check the active installed BYOND version /// - ReadInstalled = 1, - /// - /// User may check the previous BYOND version - /// - ReadPrevious = 2, + ReadActive = 1, /// /// User may change to any BYOND version /// - ChangeVersion = 4, - /// - /// User may cancel a pending installation job - /// - Cancel = 8, - /// - /// User may read the of the installation job - /// - ReadStatus = 16, + ChangeVersion = 4 } } diff --git a/src/Tgstation.Server.Client/Components/IByondClient.cs b/src/Tgstation.Server.Client/Components/IByondClient.cs index 403f6dd34a..9f9d8421c6 100644 --- a/src/Tgstation.Server.Client/Components/IByondClient.cs +++ b/src/Tgstation.Server.Client/Components/IByondClient.cs @@ -21,7 +21,7 @@ namespace Tgstation.Server.Client.Components /// /// Updates the installed BYOND /// - /// The to set to active + /// The to set to active /// The for the operation /// A representing the running operation Task SetActiveVersion(Version version, CancellationToken cancellationToken); diff --git a/src/Tgstation.Server.Host/Components/ByondManager.cs b/src/Tgstation.Server.Host/Components/ByondManager.cs index 51eed66c52..e046bcf56c 100644 --- a/src/Tgstation.Server.Host/Components/ByondManager.cs +++ b/src/Tgstation.Server.Host/Components/ByondManager.cs @@ -117,8 +117,8 @@ namespace Tgstation.Server.Host.Components return new ByondExecutableLock { - DreamDaemonPath = ioManager.ResolvePath(ioManager.ConcatPath(versionKey, byondInstaller.DreamDaemonName)), - DreamMakerPath = ioManager.ResolvePath(ioManager.ConcatPath(versionKey, byondInstaller.DreamMakerName)), + DreamDaemonPath = ioManager.ResolvePath(ioManager.ConcatPath(versionKey, BinPath, byondInstaller.DreamDaemonName)), + DreamMakerPath = ioManager.ResolvePath(ioManager.ConcatPath(versionKey, BinPath, byondInstaller.DreamMakerName)), Version = versionToUse }; } diff --git a/src/Tgstation.Server.Host/IO/SynchronousIOManager.cs b/src/Tgstation.Server.Host/IO/SynchronousIOManager.cs index 052eff0a34..cc00821fdd 100644 --- a/src/Tgstation.Server.Host/IO/SynchronousIOManager.cs +++ b/src/Tgstation.Server.Host/IO/SynchronousIOManager.cs @@ -58,18 +58,22 @@ namespace Tgstation.Server.Host.IO return false; } } - cancellationToken.ThrowIfCancellationRequested(); - file.Seek(0, SeekOrigin.Begin); - cancellationToken.ThrowIfCancellationRequested(); - file.SetLength(data.Length); + if (data != null) + { + file.Seek(0, SeekOrigin.Begin); - cancellationToken.ThrowIfCancellationRequested(); - file.Write(data, 0, data.Length); + cancellationToken.ThrowIfCancellationRequested(); + file.SetLength(data.Length); - return true; + cancellationToken.ThrowIfCancellationRequested(); + file.Write(data, 0, data.Length); + } } + if (data == null) + File.Delete(path); + return true; } } } diff --git a/src/Tgstation.Server.Host/Models/DatabaseSeeder.cs b/src/Tgstation.Server.Host/Models/DatabaseSeeder.cs index 37bf2f1c0f..acaf0e1f53 100644 --- a/src/Tgstation.Server.Host/Models/DatabaseSeeder.cs +++ b/src/Tgstation.Server.Host/Models/DatabaseSeeder.cs @@ -21,11 +21,6 @@ namespace Tgstation.Server.Host.Models /// const string DefaultAdminPassword = "ISolemlySwearToDeleteTheDataDirectory"; - /// - /// The default git repository to pull server updates from - /// - const string DefaultUpstreamRepository = "https://github.com/tgstation/tgstation-server"; - /// /// The for the /// diff --git a/tests/Tgstation.Server.Host.Tests/Security/TestAuthenticationContext.cs b/tests/Tgstation.Server.Host.Tests/Security/TestAuthenticationContext.cs index aa125813de..91af8fa215 100644 --- a/tests/Tgstation.Server.Host.Tests/Security/TestAuthenticationContext.cs +++ b/tests/Tgstation.Server.Host.Tests/Security/TestAuthenticationContext.cs @@ -43,7 +43,7 @@ namespace Tgstation.Server.Host.Security.Tests var authContext = new AuthenticationContext(null, user, instanceUser); user.AdministrationRights = AdministrationRights.EditUsers; - instanceUser.ByondRights = ByondRights.ChangeVersion | ByondRights.ReadInstalled; + instanceUser.ByondRights = ByondRights.ChangeVersion | ByondRights.ReadActive; Assert.AreEqual((int)user.AdministrationRights, authContext.GetRight(RightsType.Administration)); Assert.AreEqual((int)instanceUser.ByondRights, authContext.GetRight(RightsType.Byond)); } From 8980f057528389eeb77986bfb8b06ae9c2ebec7b Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Mon, 23 Jul 2018 23:14:53 -0400 Subject: [PATCH 14/16] Add server service to the build --- appveyor.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/appveyor.yml b/appveyor.yml index 98c9cb64f1..ec4f659cbe 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -16,6 +16,9 @@ configuration: shallow_clone: true artifacts: - path: artifacts/ServerConsole + name: Server Console + - path: artifacts/ServerService + name: Server Service cache: - ~\.nuget\packages -> **\*.csproj - C:\ProgramData\chocolatey\bin -> appveyor.yml @@ -53,6 +56,7 @@ after_test: - ps: build/UploadCoverage.ps1 - ps: build/BuildDox.ps1 - dotnet publish src/Tgstation.Server.Host.Console/Tgstation.Server.Host.Console.csproj -o ../../artifacts/ServerConsole -c %CONFIGURATION% + - ps: Copy-Item -path "src/Tgstation.Server.Host.Service/bin/($env:CONFIGURATION)" -destination ../../artifacts/ServerService -recurse deploy: - provider: GitHub release: "tgstation-server-v$(TGSVersion)" From 9d2d36e10f0e0ac895a6e861b88e6ce87c560407 Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Mon, 23 Jul 2018 23:16:04 -0400 Subject: [PATCH 15/16] Remove unrequired fciv --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index ec4f659cbe..62acd78bec 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -24,7 +24,7 @@ cache: - C:\ProgramData\chocolatey\bin -> appveyor.yml - C:\ProgramData\chocolatey\lib -> appveyor.yml install: - - choco install fciv doxygen.portable codecov + - choco install doxygen.portable codecov - nuget restore tgstation-server.sln build: project: tgstation-server.sln From 489ceaf4725806c3b9a9c31ba78f370db7d4042e Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Tue, 24 Jul 2018 10:12:58 -0400 Subject: [PATCH 16/16] Fuck --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 62acd78bec..f326ed3b2d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -56,7 +56,7 @@ after_test: - ps: build/UploadCoverage.ps1 - ps: build/BuildDox.ps1 - dotnet publish src/Tgstation.Server.Host.Console/Tgstation.Server.Host.Console.csproj -o ../../artifacts/ServerConsole -c %CONFIGURATION% - - ps: Copy-Item -path "src/Tgstation.Server.Host.Service/bin/($env:CONFIGURATION)" -destination ../../artifacts/ServerService -recurse + - ps: Copy-Item -path "src/Tgstation.Server.Host.Service/bin/$env:CONFIGURATION" -destination ../../artifacts/ServerService -recurse deploy: - provider: GitHub release: "tgstation-server-v$(TGSVersion)"