diff --git a/src/Tgstation.Server.Host/Components/DmbFactory.cs b/src/Tgstation.Server.Host/Components/DmbFactory.cs index 2fd12b08a2..cce071c63f 100644 --- a/src/Tgstation.Server.Host/Components/DmbFactory.cs +++ b/src/Tgstation.Server.Host/Components/DmbFactory.cs @@ -1,5 +1,4 @@ using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Hosting; using System; using System.Linq; using System.Threading; @@ -12,7 +11,7 @@ namespace Tgstation.Server.Host.Components /// /// Standard /// - sealed class DmbFactory : IDmbFactory, ICompileJobConsumer, IHostedService, IDisposable + sealed class DmbFactory : IDmbFactory, ICompileJobConsumer { /// /// The for the @@ -102,7 +101,12 @@ namespace Tgstation.Server.Host.Components else task = newerDmbTcs.Task; - return await task.ConfigureAwait(false); + var result = await task.ConfigureAwait(false); + //so there's currently a race condition in DreamMakerController where the setting of CompileJob.RevisionInformation and thus IDmbProvider.RevisionInformation can be delayed to after this if someone tries to start the server instantly after compiling + //This is a terrible terrible hack to get around that + //I'm sorry future me, I can't think of any other way to fix this other than giving DreamMaker an IDatabaseContext or having the controller load the CompileJob + await Task.Delay(new TimeSpan(0, 0, 10), cancellationToken).ConfigureAwait(false); + return result; } /// diff --git a/src/Tgstation.Server.Host/Components/DreamMaker.cs b/src/Tgstation.Server.Host/Components/DreamMaker.cs index 8469838b66..f49e1ad9d5 100644 --- a/src/Tgstation.Server.Host/Components/DreamMaker.cs +++ b/src/Tgstation.Server.Host/Components/DreamMaker.cs @@ -47,6 +47,10 @@ namespace Tgstation.Server.Host.Components /// The for /// readonly IInterop interop; + /// + /// The for + /// + readonly ICompileJobConsumer compileJobConsumer; /// /// Construct @@ -56,13 +60,15 @@ namespace Tgstation.Server.Host.Components /// The value of /// The value of /// The value of - public DreamMaker(IIOManager ioManager, IConfiguration configuration, IDreamDaemonExecutor dreamDaemonExecutor, IByond byond, IInterop interop) + /// The value of + public DreamMaker(IIOManager ioManager, IConfiguration configuration, IDreamDaemonExecutor dreamDaemonExecutor, IByond byond, IInterop interop, ICompileJobConsumer compileJobConsumer) { this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); this.configuration = configuration ?? throw new ArgumentNullException(nameof(configuration)); this.dreamDaemonExecutor = dreamDaemonExecutor ?? throw new ArgumentNullException(nameof(dreamDaemonExecutor)); this.byond = byond ?? throw new ArgumentNullException(nameof(byond)); this.interop = interop ?? throw new ArgumentNullException(nameof(interop)); + this.compileJobConsumer = compileJobConsumer ?? throw new ArgumentNullException(nameof(compileJobConsumer)); } /// @@ -248,6 +254,7 @@ namespace Tgstation.Server.Host.Components await configuration.SymlinkStaticFilesTo(ioManager.ResolvePath(dirB), cancellationToken).ConfigureAwait(false); await symATask.ConfigureAwait(false); } + compileJobConsumer.LoadCompileJob(job); return job; } catch diff --git a/src/Tgstation.Server.Host/Components/ICompileJobConsumer.cs b/src/Tgstation.Server.Host/Components/ICompileJobConsumer.cs index 0877e9516c..2e96eb26a9 100644 --- a/src/Tgstation.Server.Host/Components/ICompileJobConsumer.cs +++ b/src/Tgstation.Server.Host/Components/ICompileJobConsumer.cs @@ -1,10 +1,10 @@ -using System.Threading; -using System.Threading.Tasks; +using Microsoft.Extensions.Hosting; +using System; using Tgstation.Server.Host.Models; namespace Tgstation.Server.Host.Components { - interface ICompileJobConsumer + interface ICompileJobConsumer : IHostedService, IDisposable { void LoadCompileJob(CompileJob job); } diff --git a/src/Tgstation.Server.Host/Components/IInstanceFactory.cs b/src/Tgstation.Server.Host/Components/IInstanceFactory.cs index 21d905f7a4..7dfd5a667d 100644 --- a/src/Tgstation.Server.Host/Components/IInstanceFactory.cs +++ b/src/Tgstation.Server.Host/Components/IInstanceFactory.cs @@ -11,7 +11,8 @@ namespace Tgstation.Server.Host.Components /// Create an /// /// The + /// The for the operation /// A new - IInstance CreateInstance(Host.Models.Instance metadata); + IInstance CreateInstance(Host.Models.Instance metadata, IDatabaseContext databaseContext); } } \ No newline at end of file diff --git a/src/Tgstation.Server.Host/Components/IInstanceManager.cs b/src/Tgstation.Server.Host/Components/IInstanceManager.cs index 34c5f6123c..c087ad362a 100644 --- a/src/Tgstation.Server.Host/Components/IInstanceManager.cs +++ b/src/Tgstation.Server.Host/Components/IInstanceManager.cs @@ -1,5 +1,6 @@ using System.Threading; using System.Threading.Tasks; +using Tgstation.Server.Host.Models; namespace Tgstation.Server.Host.Components { @@ -19,9 +20,10 @@ namespace Tgstation.Server.Host.Components /// Online an /// /// The of the desired + /// The for the operation /// The for the operation /// A representing the running operation - Task OnlineInstance(Host.Models.Instance metadata, CancellationToken cancellationToken); + Task OnlineInstance(Host.Models.Instance metadata, IDatabaseContext databaseContext, CancellationToken cancellationToken); /// /// Offline an @@ -35,9 +37,10 @@ namespace Tgstation.Server.Host.Components /// Move an /// /// The of the desired + /// The for the operation /// The new path of the . will have this set on if the operation completes successfully /// The for the operation /// A representing the running operation - Task MoveInstance(Host.Models.Instance metadata, string newPath, CancellationToken cancellationToken); + Task MoveInstance(Host.Models.Instance metadata, IDatabaseContext databaseContext, string newPath, CancellationToken cancellationToken); } } diff --git a/src/Tgstation.Server.Host/Components/Instance.cs b/src/Tgstation.Server.Host/Components/Instance.cs index 454b1063de..a7cc23f1db 100644 --- a/src/Tgstation.Server.Host/Components/Instance.cs +++ b/src/Tgstation.Server.Host/Components/Instance.cs @@ -17,10 +17,12 @@ namespace Tgstation.Server.Host.Components public IChat Chat { get; } public IConfiguration Configuration { get; } - + + readonly ICompileJobConsumer compileJobConsumer; + readonly Api.Models.Instance metadata; - public Instance(Api.Models.Instance metadata, IRepositoryManager repositoryManager, IByond byond, IDreamMaker dreamMaker, IDreamDaemon dreamDaemon, IChat chat, IConfiguration configuration) + public Instance(Api.Models.Instance metadata, IRepositoryManager repositoryManager, IByond byond, IDreamMaker dreamMaker, IDreamDaemon dreamDaemon, IChat chat, IConfiguration configuration, ICompileJobConsumer compileJobConsumer) { this.metadata = metadata ?? throw new ArgumentNullException(nameof(metadata)); RepositoryManager = repositoryManager ?? throw new ArgumentNullException(nameof(repositoryManager)); @@ -29,6 +31,7 @@ namespace Tgstation.Server.Host.Components DreamDaemon = dreamDaemon ?? throw new ArgumentNullException(nameof(dreamDaemon)); Chat = chat ?? throw new ArgumentNullException(nameof(chat)); Configuration = configuration ?? throw new ArgumentNullException(nameof(configuration)); + this.compileJobConsumer = compileJobConsumer ?? throw new ArgumentNullException(nameof(compileJobConsumer)); } public Api.Models.Instance GetMetadata() => metadata.CloneMetadata(); @@ -40,8 +43,8 @@ namespace Tgstation.Server.Host.Components metadata.Name = newName; } - public Task StartAsync(CancellationToken cancellationToken) => Task.WhenAll(RepositoryManager.StartAsync(cancellationToken), DreamDaemon.StartAsync(cancellationToken), Chat.StartAsync(cancellationToken)); + public Task StartAsync(CancellationToken cancellationToken) => Task.WhenAll(RepositoryManager.StartAsync(cancellationToken), DreamDaemon.StartAsync(cancellationToken), Chat.StartAsync(cancellationToken), compileJobConsumer.StartAsync(cancellationToken)); - public Task StopAsync(CancellationToken cancellationToken) => Task.WhenAll(RepositoryManager.StopAsync(cancellationToken), DreamDaemon.StopAsync(cancellationToken), Chat.StopAsync(cancellationToken)); + public Task StopAsync(CancellationToken cancellationToken) => Task.WhenAll(RepositoryManager.StopAsync(cancellationToken), DreamDaemon.StopAsync(cancellationToken), Chat.StopAsync(cancellationToken), compileJobConsumer.StopAsync(cancellationToken)); } } diff --git a/src/Tgstation.Server.Host/Components/InstanceFactory.cs b/src/Tgstation.Server.Host/Components/InstanceFactory.cs index d241d749de..ed4955194e 100644 --- a/src/Tgstation.Server.Host/Components/InstanceFactory.cs +++ b/src/Tgstation.Server.Host/Components/InstanceFactory.cs @@ -1,16 +1,25 @@ using System; using Tgstation.Server.Host.Core; +using Tgstation.Server.Host.Models; namespace Tgstation.Server.Host.Components { /// sealed class InstanceFactory : IInstanceFactory { + /// + /// The for the + /// readonly IIOManager ioManager; + /// + /// Construct an + /// + /// The value of public InstanceFactory(IIOManager ioManager) => this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); + /// - public IInstance CreateInstance(Host.Models.Instance metadata) + public IInstance CreateInstance(Host.Models.Instance metadata, IDatabaseContext databaseContext) { //Create the ioManager for the instance @@ -21,6 +30,11 @@ namespace Tgstation.Server.Host.Components var byondIOManager = new ResolvingIOManager(instanceIoManager, "Byond"); var gameIoManager = new ResolvingIOManager(instanceIoManager, "Game"); var configurationIoManager = new ResolvingIOManager(instanceIoManager, "Configuration"); + var codeModificationsIoMananger = new ResolvingIOManager(instanceIoManager, "CodeModifications"); + + var dmbFactory = new DmbFactory(databaseContext, gameIoManager); + + throw new NotImplementedException(); } diff --git a/src/Tgstation.Server.Host/Components/InstanceManager.cs b/src/Tgstation.Server.Host/Components/InstanceManager.cs index ed93f70fa9..1b01e2b8e9 100644 --- a/src/Tgstation.Server.Host/Components/InstanceManager.cs +++ b/src/Tgstation.Server.Host/Components/InstanceManager.cs @@ -60,7 +60,7 @@ namespace Tgstation.Server.Host.Components } /// - public async Task MoveInstance(Host.Models.Instance instance, string newPath, CancellationToken cancellationToken) + public async Task MoveInstance(Host.Models.Instance instance, IDatabaseContext databaseContext, string newPath, CancellationToken cancellationToken) { if (newPath == null) throw new ArgumentNullException(nameof(newPath)); @@ -72,14 +72,14 @@ namespace Tgstation.Server.Host.Components var oldPath = instance.Path; await ioManager.CopyDirectory(oldPath, newPath, null, cancellationToken).ConfigureAwait(false); instance.Path = ioManager.ResolvePath(newPath); - instanceOnlineTask = OnlineInstance(instance, default); + instanceOnlineTask = OnlineInstance(instance, databaseContext, default); await ioManager.DeleteDirectory(oldPath, cancellationToken).ConfigureAwait(false); } finally { if (instance.Online) if (instanceOnlineTask == null) - await OnlineInstance(instance, default).ConfigureAwait(false); + await OnlineInstance(instance, databaseContext, default).ConfigureAwait(false); else await instanceOnlineTask.ConfigureAwait(false); } @@ -101,11 +101,11 @@ namespace Tgstation.Server.Host.Components } /// - public async Task OnlineInstance(Host.Models.Instance metadata, CancellationToken cancellationToken) + public async Task OnlineInstance(Host.Models.Instance metadata, IDatabaseContext databaseContext, CancellationToken cancellationToken) { if (metadata == null) throw new ArgumentNullException(nameof(metadata)); - var instance = instanceFactory.CreateInstance(metadata); + var instance = instanceFactory.CreateInstance(metadata, databaseContext); lock (this) { if (instances.ContainsKey(metadata.Id)) @@ -124,7 +124,7 @@ namespace Tgstation.Server.Host.Components await databaseContext.Initialize(cancellationToken).ConfigureAwait(false); var dbInstances = databaseContext.Instances.Where(x => x.Online).Include(x => x.RepositorySettings).Include(x => x.ChatSettings).Include(x => x.DreamDaemonSettings).ToAsyncEnumerable(); var tasks = new List(); - await dbInstances.ForEachAsync(metadata => tasks.Add(OnlineInstance(metadata, cancellationToken)), cancellationToken).ConfigureAwait(false); + await dbInstances.ForEachAsync(metadata => tasks.Add(OnlineInstance(metadata, databaseContext, cancellationToken)), cancellationToken).ConfigureAwait(false); await Task.WhenAll(tasks).ConfigureAwait(false); } }