Skeleton web app

This commit is contained in:
Cyberboss
2018-04-06 23:52:34 -04:00
parent 7a106d30ee
commit 267cecab91
12 changed files with 132 additions and 58 deletions
+2 -3
View File
@@ -7,7 +7,7 @@ namespace Tgstation.Server.Host.Startup
/// <summary>
/// Represents the host
/// </summary>
public interface IServer : IDisposable
public interface IServer
{
/// <summary>
/// The path to the updated assembly to run if any. Populated once <see cref="RunAsync(string[], CancellationToken)"/> returns
@@ -17,9 +17,8 @@ namespace Tgstation.Server.Host.Startup
/// <summary>
/// Runs the <see cref="IServer"/>
/// </summary>
/// <param name="args">The arguments for the <see cref="IServer"/></param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
/// <returns>A <see cref="Task"/> representing the running operation</returns>
Task RunAsync(string[] args, CancellationToken cancellationToken);
Task RunAsync(CancellationToken cancellationToken);
}
}
@@ -5,10 +5,11 @@
/// </summary>
public interface IServerFactory
{
/// <summary>
/// Create a <see cref="IServer"/>
/// </summary>
/// <returns>A new <see cref="IServer"/></returns>
IServer CreateServer();
/// <summary>
/// Create a <see cref="IServer"/>
/// </summary>
/// <param name="args">The arguments for the <see cref="IServer"/></param>
/// <returns>A new <see cref="IServer"/></returns>
IServer CreateServer(string[] args);
}
}
@@ -25,8 +25,9 @@ namespace Tgstation.Server.Host.Watchdog
/// <summary>
/// Loads the <see cref="Assembly"/> at <see cref="assemblyPath"/> and creates an <see cref="IServer"/> from it
/// </summary>
/// <param name="args">The arguments for the <see cref="IServer"/></param>
/// <returns>A new <see cref="IServer"/></returns>
public IServer CreateServer()
public IServer CreateServer(string[] args)
{
var assembly = LoadFromAssemblyPath(assemblyPath);
//find the IServerFactory implementation
@@ -35,7 +36,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();
return serverFactory.CreateServer(args);
}
//honestly have no idea what this is for, but the examples i see just return null and it seems to work just fine
+12 -17
View File
@@ -43,24 +43,19 @@ namespace Tgstation.Server.Host.Watchdog
//first run the host we started with
var serverFactory = initialServerFactory;
var assemblyPath = serverFactory.GetType().Assembly.Location;
do
{
string updatePath;
using (var server = serverFactory.CreateServer())
{
serverFactory = null;
await server.RunAsync(args, cancellationToken).ConfigureAwait(false);
updatePath = server.UpdatePath;
}
do
{
var server = serverFactory.CreateServer(args);
await server.RunAsync(cancellationToken).ConfigureAwait(false);
if (updatePath == null)
break;
activeAssemblyDeleter.DeleteActiveAssembly(assemblyPath);
File.Move(updatePath, assemblyPath);
serverFactory = isolatedAssemblyLoader.CreateIsolatedServerFactory(assemblyPath);
}
while (!cancellationToken.IsCancellationRequested);
if (server.UpdatePath == null)
break;
activeAssemblyDeleter.DeleteActiveAssembly(assemblyPath);
File.Move(server.UpdatePath, assemblyPath);
serverFactory = isolatedAssemblyLoader.CreateIsolatedServerFactory(assemblyPath);
}
while (!cancellationToken.IsCancellationRequested);
}
}
}
@@ -0,0 +1,76 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Globalization;
namespace Tgstation.Server.Host.Core
{
/// <summary>
/// Configures the ASP.NET Core web application
/// </summary>
sealed class Application
{
/// <summary>
/// The <see cref="IConfiguration"/> for the <see cref="Application"/>
/// </summary>
readonly IConfiguration configuration;
/// <summary>
/// Construct an <see cref="Application"/>
/// </summary>
/// <param name="configuration">The value of <see cref="configuration"/></param>
public Application(IConfiguration configuration) => this.configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
/// <summary>
/// Configure dependency injected services
/// </summary>
/// <param name="services">The <see cref="IServiceCollection"/> to configure</param>
#pragma warning disable CA1822 // Mark members as static
public void ConfigureServices(IServiceCollection services)
#pragma warning restore CA1822 // Mark members as static
{
if (services == null)
throw new ArgumentNullException(nameof(services));
services.AddMvc();
services.AddOptions();
services.AddLocalization();
}
/// <summary>
/// Configure the <see cref="Application"/>
/// </summary>
/// <param name="applicationBuilder">The <see cref="IApplicationBuilder"/> to configure</param>
/// <param name="hostingEnvironment">The <see cref="IHostingEnvironment"/> of the <see cref="Application"/></param>
public void Configure(IApplicationBuilder applicationBuilder, IHostingEnvironment hostingEnvironment)
{
if (applicationBuilder == null)
throw new ArgumentNullException(nameof(applicationBuilder));
if (hostingEnvironment == null)
throw new ArgumentNullException(nameof(hostingEnvironment));
if (hostingEnvironment.IsDevelopment())
applicationBuilder.UseDeveloperExceptionPage();
var defaultCulture = new CultureInfo("en");
var supportedCultures = new List<CultureInfo>
{
defaultCulture
};
CultureInfo.CurrentCulture = defaultCulture;
CultureInfo.CurrentUICulture = defaultCulture;
applicationBuilder.UseRequestLocalization(new RequestLocalizationOptions
{
SupportedCultures = supportedCultures,
SupportedUICultures = supportedCultures,
});
applicationBuilder.UseMvc();
}
}
}
+21 -4
View File
@@ -1,5 +1,9 @@
using System.Threading;
using Microsoft.AspNetCore.Hosting;
using System;
using System.Diagnostics.CodeAnalysis;
using System.Threading;
using System.Threading.Tasks;
using Tgstation.Server.Host.Core;
using Tgstation.Server.Host.Startup;
namespace Tgstation.Server.Host
@@ -10,10 +14,23 @@ namespace Tgstation.Server.Host
/// <inheritdoc />
public string UpdatePath => null;
/// <inheritdoc />
public void Dispose() { }
/// <summary>
/// The <see cref="IWebHostBuilder"/> for the <see cref="Server"/>
/// </summary>
readonly IWebHostBuilder webHostBuilder;
/// <summary>
/// Construct a <see cref="Server"/>
/// </summary>
/// <param name="webHostBuilder">The value of <see cref="webHostBuilder"/></param>
public Server(IWebHostBuilder webHostBuilder) => this.webHostBuilder = webHostBuilder ?? throw new ArgumentNullException(nameof(webHostBuilder));
/// <inheritdoc />
public Task RunAsync(string[] args, CancellationToken cancellationToken) => Task.CompletedTask;
[ExcludeFromCodeCoverage]
public async Task RunAsync(CancellationToken cancellationToken)
{
using (var webHost = webHostBuilder.UseStartup<Application>().Build())
await webHost.RunAsync(cancellationToken).ConfigureAwait(false);
}
}
}
+4 -2
View File
@@ -1,4 +1,6 @@
using Tgstation.Server.Host.Startup;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Tgstation.Server.Host.Startup;
namespace Tgstation.Server.Host
{
@@ -6,6 +8,6 @@ namespace Tgstation.Server.Host
public sealed class ServerFactory : IServerFactory
{
/// <inheritdoc />
public IServer CreateServer() => new Server();
public IServer CreateServer(string[] args) => new Server(WebHost.CreateDefaultBuilder(args));
}
}
@@ -18,6 +18,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore" Version="2.0.2" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.0.3" />
<PackageReference Include="Octokit" Version="0.29.0" />
</ItemGroup>
@@ -1,19 +0,0 @@
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Tgstation.Server.Host.Tests
{
[TestClass]
public sealed class TestServer
{
[TestMethod]
public async Task TestRunAndDispose()
{
using (var server = new Server())
{
await server.RunAsync(null, default).ConfigureAwait(false);
Assert.IsNull(server.UpdatePath);
}
}
}
}
@@ -9,8 +9,9 @@
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.0" />
<PackageReference Include="MSTest.TestAdapter" Version="1.2.0" />
<PackageReference Include="MSTest.TestFramework" Version="1.2.0" />
<PackageReference Include="Moq" Version="4.8.2" />
<PackageReference Include="MSTest.TestAdapter" Version="1.2.1" />
<PackageReference Include="MSTest.TestFramework" Version="1.2.1" />
</ItemGroup>
<ItemGroup>
@@ -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());
Assert.IsNotNull(isf.CreateServer(Array.Empty<string>()));
}
}
}
@@ -26,7 +26,7 @@ namespace Tgstation.Server.Host.Watchdog.Tests
{
readonly IServer server;
public MockServerFactory(IServer server) => this.server = server;
public IServer CreateServer() => server;
public IServer CreateServer(string[] args) => server;
}
[TestMethod]
@@ -41,7 +41,7 @@ namespace Tgstation.Server.Host.Watchdog.Tests
using (var cts = new CancellationTokenSource())
{
mockServer.Setup(x => x.RunAsync(It.IsNotNull<string[]>(), cts.Token)).Returns(Task.CompletedTask).Verifiable();
mockServer.Setup(x => x.RunAsync(cts.Token)).Returns(Task.CompletedTask).Verifiable();
await wd.RunAsync(Array.Empty<string>(), cts.Token).ConfigureAwait(false);
mockServer.VerifyAll();
}
@@ -62,7 +62,7 @@ namespace Tgstation.Server.Host.Watchdog.Tests
using (var cts = new CancellationTokenSource())
{
int count = 0;
mockServer.Setup(x => x.RunAsync(It.IsNotNull<string[]>(), cts.Token)).Callback(() =>
mockServer.Setup(x => x.RunAsync(cts.Token)).Callback(() =>
{
if (++count > 1)
cts.Cancel();