diff --git a/src/Tgstation.Server.Api/Tgstation.Server.Api.csproj b/src/Tgstation.Server.Api/Tgstation.Server.Api.csproj index 1ccca2d0fb..96b02fd263 100644 --- a/src/Tgstation.Server.Api/Tgstation.Server.Api.csproj +++ b/src/Tgstation.Server.Api/Tgstation.Server.Api.csproj @@ -33,9 +33,9 @@ - + - + diff --git a/src/Tgstation.Server.Host.Watchdog/IsolatedServerFactory.cs b/src/Tgstation.Server.Host.Watchdog/IsolatedServerFactory.cs index 2545747721..b51de730e9 100644 --- a/src/Tgstation.Server.Host.Watchdog/IsolatedServerFactory.cs +++ b/src/Tgstation.Server.Host.Watchdog/IsolatedServerFactory.cs @@ -25,9 +25,10 @@ namespace Tgstation.Server.Host.Watchdog /// /// Loads the at and creates an from it /// - /// The arguments for the + /// The arguments for the + /// The updatePath for the /// A new - public IServer CreateServer(string[] args) + public IServer CreateServer(string[] args, string updatePath) { var assembly = LoadFromAssemblyPath(assemblyPath); //find the IServerFactory implementation @@ -36,7 +37,7 @@ namespace Tgstation.Server.Host.Watchdog var serverFactoryImplementationType = assembly.GetTypes().Where(x => serverFactoryInterfaceType.IsAssignableFrom(x)).First(); var serverFactory = (IServerFactory)Activator.CreateInstance(serverFactoryImplementationType); - return serverFactory.CreateServer(args); + return serverFactory.CreateServer(args, updatePath); } //honestly have no idea what this is for, but the examples i see just return null and it seems to work just fine diff --git a/src/Tgstation.Server.Host.Watchdog/Watchdog.cs b/src/Tgstation.Server.Host.Watchdog/Watchdog.cs index 23f4a8968d..07372198e5 100644 --- a/src/Tgstation.Server.Host.Watchdog/Watchdog.cs +++ b/src/Tgstation.Server.Host.Watchdog/Watchdog.cs @@ -57,27 +57,36 @@ namespace Tgstation.Server.Host.Watchdog logger.LogTrace("Determining location of host assembly..."); var assemblyPath = serverFactory.GetType().Assembly.Location; logger.LogDebug("Path to initial host assembly: {0}", assemblyPath); + var assemblyName = Path.GetFileName(assemblyPath); + const string UpdatePath = "Updates"; + var newAssemblyDirectory = Path.Combine(Path.GetDirectoryName(assemblyPath), UpdatePath); var firstIteration = true; do using (logger.BeginScope("Host invocation")) { - var server = serverFactory.CreateServer(args); - logger.LogTrace("Running server..."); - await server.RunAsync(cancellationToken).ConfigureAwait(false); - logger.LogInformation("Active host exited."); + Guid updateGuid; + using (var server = serverFactory.CreateServer(args, newAssemblyDirectory)) + { + logger.LogTrace("Running server..."); + await server.RunAsync(cancellationToken).ConfigureAwait(false); + logger.LogInformation("Active host exited."); - if (server.UpdatePath == null) - break; + if (!server.UpdateGuid.HasValue) + break; + updateGuid = server.UpdateGuid.Value; + } - logger.LogInformation("Update path is set to \"{0}\", attempting host assembly hotswap...", server.UpdatePath); + logger.LogInformation("Update path is set to \"{0}\", attempting host assembly hotswap...", updateGuid); GC.Collect(Int32.MaxValue, GCCollectionMode.Forced, true, true); - logger.LogTrace("Deleting old host assembly"); - activeAssemblyDeleter.DeleteActiveAssembly(assemblyPath); - logger.LogTrace("Moving new host assembly in place..."); - File.Move(server.UpdatePath, assemblyPath); + if (!firstIteration) + { + logger.LogTrace("Deleting old host assembly"); + //TODO: make this use directories + //activeAssemblyDeleter.DeleteActiveAssembly(newAssemblyDirectory); + } logger.LogTrace("Atttempting to create new server factory..."); - serverFactory = isolatedAssemblyLoader.CreateIsolatedServerFactory(assemblyPath); + serverFactory = isolatedAssemblyLoader.CreateIsolatedServerFactory(Path.Combine(newAssemblyDirectory, updateGuid.ToString(), assemblyName)); firstIteration = false; } while (!cancellationToken.IsCancellationRequested); diff --git a/src/Tgstation.Server.Host/IO/DefaultIOManager.cs b/src/Tgstation.Server.Host/IO/DefaultIOManager.cs index b24653f8fe..a5f2b122c7 100644 --- a/src/Tgstation.Server.Host/IO/DefaultIOManager.cs +++ b/src/Tgstation.Server.Host/IO/DefaultIOManager.cs @@ -272,7 +272,7 @@ namespace Tgstation.Server.Host.IO zipFileBytes = null; using (var archive = new ZipArchive(ms)) { - string GetEntryName(ZipArchiveEntry entry) => ConcatPath(path, GetDirectoryName(entry.FullName)); + string GetEntryName(ZipArchiveEntry entry) => ConcatPath(path, entry.FullName); //create directories first await Task.WhenAll(archive.Entries.Where(x => x.Name.Length == 0).Select(x => CreateDirectory(GetEntryName(x), cancellationToken))).ConfigureAwait(false); //extract files diff --git a/src/Tgstation.Server.Host/ServerFactory.cs b/src/Tgstation.Server.Host/ServerFactory.cs index 810ef924e2..ffe440055d 100644 --- a/src/Tgstation.Server.Host/ServerFactory.cs +++ b/src/Tgstation.Server.Host/ServerFactory.cs @@ -7,6 +7,6 @@ namespace Tgstation.Server.Host public sealed class ServerFactory : IServerFactory { /// - public IServer CreateServer(string[] args) => new Server(WebHost.CreateDefaultBuilder(args)); + public IServer CreateServer(string[] args, string updatePath) => new Server(WebHost.CreateDefaultBuilder(args), updatePath); } } diff --git a/tests/Tgstation.Server.Host.Tests/Core/TestApplication.cs b/tests/Tgstation.Server.Host.Tests/Core/TestApplication.cs index 22833bacdb..6a8eb5d68a 100644 --- a/tests/Tgstation.Server.Host.Tests/Core/TestApplication.cs +++ b/tests/Tgstation.Server.Host.Tests/Core/TestApplication.cs @@ -4,14 +4,16 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.VisualStudio.TestTools.UnitTesting; using System; using System.IO; +using System.Threading; using System.Threading.Tasks; +using Tgstation.Server.Host.IO; namespace Tgstation.Server.Host.Core.Tests { [TestClass] public sealed class TestApplication : IServerUpdater { - public void ApplyUpdate(string updatePath) => throw new NotImplementedException(); + public Task ApplyUpdate(byte[] updateZipData, IIOManager ioManager, CancellationToken cancellationToken) => throw new NotImplementedException(); public void RegisterForUpdate(Action action) => throw new NotImplementedException(); diff --git a/tests/Tgstation.Server.Host.Watchdog.Tests/TestIsolatedServerFactory.cs b/tests/Tgstation.Server.Host.Watchdog.Tests/TestIsolatedServerFactory.cs index ab382bff97..384139308b 100644 --- a/tests/Tgstation.Server.Host.Watchdog.Tests/TestIsolatedServerFactory.cs +++ b/tests/Tgstation.Server.Host.Watchdog.Tests/TestIsolatedServerFactory.cs @@ -20,7 +20,7 @@ namespace Tgstation.Server.Host.Watchdog.Tests public void TestLoading() { var isf = new IsolatedServerFactory(typeof(ServerFactory).Assembly.Location); - Assert.IsNotNull(isf.CreateServer(Array.Empty())); + Assert.IsNotNull(isf.CreateServer(Array.Empty(), String.Empty)); } } } diff --git a/tests/Tgstation.Server.Host.Watchdog.Tests/TestWatchdog.cs b/tests/Tgstation.Server.Host.Watchdog.Tests/TestWatchdog.cs index 56ec75351a..8f233120d5 100644 --- a/tests/Tgstation.Server.Host.Watchdog.Tests/TestWatchdog.cs +++ b/tests/Tgstation.Server.Host.Watchdog.Tests/TestWatchdog.cs @@ -29,7 +29,7 @@ namespace Tgstation.Server.Host.Watchdog.Tests { readonly IServer server; public MockServerFactory(IServer server) => this.server = server; - public IServer CreateServer(string[] args) => server; + public IServer CreateServer(string[] args, string updatePath) => server; } [TestMethod] @@ -50,34 +50,5 @@ namespace Tgstation.Server.Host.Watchdog.Tests mockServer.VerifyAll(); } } - - [TestMethod] - public async Task TestRunAsyncWithUpdate() - { - var mockServer = new Mock(); - mockServer.Setup(x => x.UpdatePath).Returns(GetType().Assembly.Location).Verifiable(); - var mockServerFactory = new MockServerFactory(mockServer.Object); - var mockActiveAssemblyDeleter = new Mock(); - var mockIsolatedServerContextFactory = new Mock(); - mockIsolatedServerContextFactory.Setup(x => x.CreateIsolatedServerFactory(GetType().Assembly.Location)).Returns(mockServerFactory).Verifiable(); - var mockLogger = new LoggerFactory().CreateLogger(); - - var wd = new Watchdog(mockServerFactory, mockActiveAssemblyDeleter.Object, mockIsolatedServerContextFactory.Object, mockLogger); - - using (var cts = new CancellationTokenSource()) - { - int count = 0; - mockServer.Setup(x => x.RunAsync(cts.Token)).Callback(() => - { - if (++count > 1) - cts.Cancel(); - }).Returns(Task.CompletedTask).Verifiable(); - await wd.RunAsync(Array.Empty(), cts.Token).ConfigureAwait(false); - - mockServer.VerifyAll(); - mockActiveAssemblyDeleter.Verify(x => x.DeleteActiveAssembly(GetType().Assembly.Location), Times.Exactly(2)); - mockIsolatedServerContextFactory.VerifyAll(); - } - } } }