mirror of
https://github.com/tgstation/tgstation-server.git
synced 2026-08-22 04:27:19 +01:00
Add support for changing console title
- Move `VersionExtensions` to `Tgstation.Server.Common`. - Fix Host watchdog API version specifying `Revision`.
This commit is contained in:
@@ -12,6 +12,7 @@ using Microsoft.Net.Http.Headers;
|
||||
|
||||
using Tgstation.Server.Api.Models;
|
||||
using Tgstation.Server.Api.Properties;
|
||||
using Tgstation.Server.Common.Extensions;
|
||||
|
||||
namespace Tgstation.Server.Api
|
||||
{
|
||||
|
||||
@@ -48,4 +48,8 @@
|
||||
<ItemGroup>
|
||||
<AdditionalFiles Include="../../build/stylecop.json" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Tgstation.Server.Common\Tgstation.Server.Common.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Tgstation.Server.Api\Tgstation.Server.Api.csproj" />
|
||||
<ProjectReference Include="..\Tgstation.Server.Common\Tgstation.Server.Common.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace Tgstation.Server.Api
|
||||
namespace Tgstation.Server.Common.Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Extensions for the <see cref="Version"/> class.
|
||||
@@ -1,10 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
using Tgstation.Server.Common.Extensions;
|
||||
using Tgstation.Server.Host.Watchdog;
|
||||
|
||||
namespace Tgstation.Server.Host.Console
|
||||
@@ -34,6 +35,8 @@ namespace Tgstation.Server.Host.Console
|
||||
/// <returns>A <see cref="Task"/> representing the running operation.</returns>
|
||||
internal static async Task<int> Main(string[] args)
|
||||
{
|
||||
System.Console.Title = $"tgstation-server Host Watchdog v{Assembly.GetExecutingAssembly().GetName().Version.Semver()}";
|
||||
|
||||
var arguments = new List<string>(args);
|
||||
var trace = arguments.Remove("--trace-host-watchdog");
|
||||
var debug = arguments.Remove("--debug-host-watchdog");
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Tgstation.Server.Common\Tgstation.Server.Common.csproj" />
|
||||
<ProjectReference Include="..\Tgstation.Server.Host.Common\Tgstation.Server.Host.Common.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -10,7 +10,7 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
using Tgstation.Server.Common.Extensions;
|
||||
using Tgstation.Server.Host.Common;
|
||||
|
||||
namespace Tgstation.Server.Host.Watchdog
|
||||
@@ -109,7 +109,7 @@ namespace Tgstation.Server.Host.Watchdog
|
||||
return false;
|
||||
}
|
||||
|
||||
var watchdogVersion = executingAssembly.GetName().Version.ToString();
|
||||
var watchdogVersion = executingAssembly.GetName().Version.Semver().ToString();
|
||||
|
||||
while (!cancellationToken.IsCancellationRequested)
|
||||
using (logger.BeginScope("Host invocation"))
|
||||
|
||||
@@ -87,6 +87,11 @@ namespace Tgstation.Server.Host.Components
|
||||
/// </summary>
|
||||
readonly ISwarmServiceController swarmServiceController;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IConsole"/> for the <see cref="InstanceManager"/>.
|
||||
/// </summary>
|
||||
readonly IConsole console;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="ILogger"/> for the <see cref="InstanceManager"/>.
|
||||
/// </summary>
|
||||
@@ -132,6 +137,11 @@ namespace Tgstation.Server.Host.Components
|
||||
/// </summary>
|
||||
readonly CancellationTokenSource shutdownCancellationTokenSource;
|
||||
|
||||
/// <summary>
|
||||
/// The original <see cref="IConsole.Title"/> of <see cref="console"/>.
|
||||
/// </summary>
|
||||
readonly string originalConsoleTitle;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="Task"/> returned by <see cref="Initialize(CancellationToken)"/>.
|
||||
/// </summary>
|
||||
@@ -155,6 +165,7 @@ namespace Tgstation.Server.Host.Components
|
||||
/// <param name="asyncDelayer">The value of <see cref="asyncDelayer"/>.</param>
|
||||
/// <param name="serverPortProvider">The value of <see cref="serverPortProvider"/>.</param>
|
||||
/// <param name="swarmServiceController">The value of <see cref="swarmServiceController"/>.</param>
|
||||
/// <param name="console">The value of <see cref="console"/>.</param>
|
||||
/// <param name="generalConfigurationOptions">The <see cref="IOptions{TOptions}"/> containing the value of <see cref="generalConfiguration"/>.</param>
|
||||
/// <param name="swarmConfigurationOptions">The <see cref="IOptions{TOptions}"/> containing the value of <see cref="swarmConfiguration"/>.</param>
|
||||
/// <param name="logger">The value of <see cref="logger"/>.</param>
|
||||
@@ -169,6 +180,7 @@ namespace Tgstation.Server.Host.Components
|
||||
IAsyncDelayer asyncDelayer,
|
||||
IServerPortProvider serverPortProvider,
|
||||
ISwarmServiceController swarmServiceController,
|
||||
IConsole console,
|
||||
IOptions<GeneralConfiguration> generalConfigurationOptions,
|
||||
IOptions<SwarmConfiguration> swarmConfigurationOptions,
|
||||
ILogger<InstanceManager> logger)
|
||||
@@ -183,10 +195,13 @@ namespace Tgstation.Server.Host.Components
|
||||
this.asyncDelayer = asyncDelayer ?? throw new ArgumentNullException(nameof(asyncDelayer));
|
||||
this.serverPortProvider = serverPortProvider ?? throw new ArgumentNullException(nameof(serverPortProvider));
|
||||
this.swarmServiceController = swarmServiceController ?? throw new ArgumentNullException(nameof(swarmServiceController));
|
||||
this.console = console ?? throw new ArgumentNullException(nameof(console));
|
||||
generalConfiguration = generalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(generalConfigurationOptions));
|
||||
swarmConfiguration = swarmConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(swarmConfigurationOptions));
|
||||
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
|
||||
originalConsoleTitle = console.Title;
|
||||
|
||||
instances = new Dictionary<long, ReferenceCountingContainer<IInstance, InstanceWrapper>>();
|
||||
bridgeHandlers = new Dictionary<string, IBridgeHandler>();
|
||||
readyTcs = new TaskCompletionSource();
|
||||
@@ -426,42 +441,49 @@ namespace Tgstation.Server.Host.Components
|
||||
/// <inheritdoc />
|
||||
public async Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
using (cancellationToken.Register(shutdownCancellationTokenSource.Cancel))
|
||||
try
|
||||
{
|
||||
logger.LogDebug("Stopping instance manager...");
|
||||
|
||||
if (!startupTask.IsCompleted)
|
||||
try
|
||||
{
|
||||
using (cancellationToken.Register(shutdownCancellationTokenSource.Cancel))
|
||||
try
|
||||
{
|
||||
logger.LogTrace("Interrupting startup task...");
|
||||
startupCancellationTokenSource.Cancel();
|
||||
await startupTask;
|
||||
logger.LogDebug("Stopping instance manager...");
|
||||
|
||||
if (!startupTask.IsCompleted)
|
||||
{
|
||||
logger.LogTrace("Interrupting startup task...");
|
||||
startupCancellationTokenSource.Cancel();
|
||||
await startupTask;
|
||||
}
|
||||
|
||||
var instanceFactoryStopTask = instanceFactory.StopAsync(cancellationToken);
|
||||
await jobService.StopAsync(cancellationToken);
|
||||
|
||||
async Task OfflineInstanceImmediate(IInstance instance, CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
await instance.StopAsync(cancellationToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "Instance shutdown exception!");
|
||||
}
|
||||
}
|
||||
|
||||
await Task.WhenAll(instances.Select(x => OfflineInstanceImmediate(x.Value.Instance, cancellationToken)));
|
||||
await instanceFactoryStopTask;
|
||||
|
||||
await swarmServiceController.Shutdown(cancellationToken);
|
||||
}
|
||||
|
||||
var instanceFactoryStopTask = instanceFactory.StopAsync(cancellationToken);
|
||||
await jobService.StopAsync(cancellationToken);
|
||||
|
||||
async Task OfflineInstanceImmediate(IInstance instance, CancellationToken cancellationToken)
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
await instance.StopAsync(cancellationToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "Instance shutdown exception!");
|
||||
}
|
||||
console.Title = originalConsoleTitle;
|
||||
}
|
||||
|
||||
await Task.WhenAll(instances.Select(x => OfflineInstanceImmediate(x.Value.Instance, cancellationToken)));
|
||||
await instanceFactoryStopTask;
|
||||
|
||||
await swarmServiceController.Shutdown(cancellationToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogCritical(ex, "Instance manager stop exception!");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogCritical(ex, "Instance manager stop exception!");
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -535,6 +557,7 @@ namespace Tgstation.Server.Host.Components
|
||||
try
|
||||
{
|
||||
logger.LogInformation("{versionString}", assemblyInformationProvider.VersionString);
|
||||
console.Title = assemblyInformationProvider.VersionString;
|
||||
|
||||
CheckSystemCompatibility();
|
||||
|
||||
|
||||
@@ -13,8 +13,8 @@ using Newtonsoft.Json;
|
||||
|
||||
using Serilog.Context;
|
||||
|
||||
using Tgstation.Server.Api;
|
||||
using Tgstation.Server.Api.Models;
|
||||
using Tgstation.Server.Common.Extensions;
|
||||
using Tgstation.Server.Host.Components.Byond;
|
||||
using Tgstation.Server.Host.Components.Chat;
|
||||
using Tgstation.Server.Host.Components.Deployment;
|
||||
|
||||
@@ -10,9 +10,9 @@ using Byond.TopicSender;
|
||||
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
using Tgstation.Server.Api;
|
||||
using Tgstation.Server.Api.Models;
|
||||
using Tgstation.Server.Api.Models.Internal;
|
||||
using Tgstation.Server.Common.Extensions;
|
||||
using Tgstation.Server.Host.Components.Byond;
|
||||
using Tgstation.Server.Host.Components.Chat;
|
||||
using Tgstation.Server.Host.Components.Deployment;
|
||||
|
||||
@@ -22,6 +22,7 @@ using Serilog.Context;
|
||||
using Tgstation.Server.Api;
|
||||
using Tgstation.Server.Api.Models;
|
||||
using Tgstation.Server.Api.Models.Response;
|
||||
using Tgstation.Server.Common.Extensions;
|
||||
using Tgstation.Server.Host.Database;
|
||||
using Tgstation.Server.Host.Extensions;
|
||||
using Tgstation.Server.Host.Models;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
using Tgstation.Server.Api;
|
||||
using Tgstation.Server.Common.Extensions;
|
||||
|
||||
using YamlDotNet.Core;
|
||||
using YamlDotNet.Core.Events;
|
||||
|
||||
@@ -3,19 +3,33 @@ using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Tgstation.Server.Host.Extensions;
|
||||
using Tgstation.Server.Host.System;
|
||||
|
||||
namespace Tgstation.Server.Host.IO
|
||||
{
|
||||
/// <inheritdoc />
|
||||
sealed class Console : IConsole, IDisposable
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public string Title
|
||||
{
|
||||
get => platformIdentifier.IsWindows
|
||||
? global::System.Console.Title
|
||||
: null;
|
||||
set => global::System.Console.Title = value;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Available => Environment.UserInteractive;
|
||||
|
||||
/// <inheritdoc />
|
||||
public CancellationToken CancelKeyPress => cancelKeyCts.Token;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IPlatformIdentifier"/> for the <see cref="Console"/>.
|
||||
/// </summary>
|
||||
readonly IPlatformIdentifier platformIdentifier;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="CancellationTokenSource"/> for <see cref="CancelKeyPress"/>.
|
||||
/// </summary>
|
||||
@@ -29,8 +43,11 @@ namespace Tgstation.Server.Host.IO
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Console"/> class.
|
||||
/// </summary>
|
||||
public Console()
|
||||
/// <param name="platformIdentifier">The value of <see cref="platformIdentifier"/>.</param>
|
||||
public Console(IPlatformIdentifier platformIdentifier)
|
||||
{
|
||||
this.platformIdentifier = platformIdentifier ?? throw new ArgumentNullException(nameof(platformIdentifier));
|
||||
|
||||
cancelKeyCts = new CancellationTokenSource();
|
||||
global::System.Console.CancelKeyPress += (sender, e) =>
|
||||
{
|
||||
|
||||
@@ -8,6 +8,11 @@ namespace Tgstation.Server.Host.IO
|
||||
/// </summary>
|
||||
interface IConsole
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="IConsole"/> window's title. Can return <see langword="null"/> if getting the console title is not supported.
|
||||
/// </summary>
|
||||
string Title { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If the <see cref="IConsole"/> is visible to the user.
|
||||
/// </summary>
|
||||
|
||||
@@ -1073,8 +1073,18 @@ namespace Tgstation.Server.Host.Setup
|
||||
await console.WriteAsync("Aborting setup!", true, default);
|
||||
}
|
||||
|
||||
// Link passed cancellationToken with cancel key press
|
||||
Task finalTask = Task.CompletedTask;
|
||||
string originalConsoleTitle = null;
|
||||
void SetConsoleTitle()
|
||||
{
|
||||
if (originalConsoleTitle != null)
|
||||
return;
|
||||
|
||||
originalConsoleTitle = console.Title;
|
||||
console.Title = $"{assemblyInformationProvider.VersionString} Setup Wizard";
|
||||
}
|
||||
|
||||
// Link passed cancellationToken with cancel key press
|
||||
using (var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, console.CancelKeyPress))
|
||||
using ((cancellationToken = cts.Token).Register(() => finalTask = HandleSetupCancel()))
|
||||
try
|
||||
@@ -1106,6 +1116,7 @@ namespace Tgstation.Server.Host.Setup
|
||||
{
|
||||
if (forceRun)
|
||||
{
|
||||
SetConsoleTitle();
|
||||
await console.WriteAsync(String.Format(CultureInfo.InvariantCulture, "The configuration settings are requesting the setup wizard be run, but you already appear to have a configuration file ({0})!", userConfigFileName), true, cancellationToken);
|
||||
|
||||
forceRun = await PromptYesNo("Continue running setup wizard?", false, cancellationToken);
|
||||
@@ -1115,6 +1126,8 @@ namespace Tgstation.Server.Host.Setup
|
||||
return;
|
||||
}
|
||||
|
||||
SetConsoleTitle();
|
||||
|
||||
// flush the logs to prevent console conflicts
|
||||
await asyncDelayer.Delay(TimeSpan.FromSeconds(1), cancellationToken);
|
||||
|
||||
@@ -1123,6 +1136,8 @@ namespace Tgstation.Server.Host.Setup
|
||||
finally
|
||||
{
|
||||
await finalTask;
|
||||
if (originalConsoleTitle != null)
|
||||
console.Title = originalConsoleTitle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
using System.Net.Http.Headers;
|
||||
using System.Reflection;
|
||||
|
||||
using Tgstation.Server.Api;
|
||||
using Tgstation.Server.Common.Extensions;
|
||||
using Tgstation.Server.Host.Common;
|
||||
|
||||
namespace Tgstation.Server.Host.System
|
||||
|
||||
@@ -140,7 +140,6 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Tgstation.Server.Api\Tgstation.Server.Api.csproj" />
|
||||
<ProjectReference Include="..\Tgstation.Server.Common\Tgstation.Server.Common.csproj" />
|
||||
<ProjectReference Include="..\Tgstation.Server.Host.Common\Tgstation.Server.Host.Common.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
using Tgstation.Server.Api;
|
||||
using Tgstation.Server.Api.Models;
|
||||
using Tgstation.Server.Api.Models.Response;
|
||||
using Tgstation.Server.Common.Extensions;
|
||||
using Tgstation.Server.Host.Controllers;
|
||||
|
||||
namespace Tgstation.Server.Host.Utils
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System;
|
||||
|
||||
using Tgstation.Server.Api;
|
||||
using Tgstation.Server.Common.Extensions;
|
||||
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
|
||||
@@ -4,15 +4,23 @@ using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Tgstation.Server.Host.System;
|
||||
|
||||
namespace Tgstation.Server.Host.IO.Tests
|
||||
{
|
||||
[TestClass]
|
||||
public sealed class TestConsole
|
||||
{
|
||||
[TestMethod]
|
||||
public void TestContructionThrows()
|
||||
{
|
||||
Assert.ThrowsException<ArgumentNullException>(() => new Console(null));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task TestWriteLine()
|
||||
{
|
||||
var console = new Console();
|
||||
var console = new Console(new PlatformIdentifier());
|
||||
await Assert.ThrowsExceptionAsync<InvalidOperationException>(() => console.WriteAsync(null, false, default));
|
||||
try
|
||||
{
|
||||
@@ -28,7 +36,7 @@ namespace Tgstation.Server.Host.IO.Tests
|
||||
[TestMethod]
|
||||
public void TestUserInteractive()
|
||||
{
|
||||
var console = new Console();
|
||||
var console = new Console(new PlatformIdentifier());
|
||||
Assert.AreEqual(Environment.UserInteractive, console.Available);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,11 +9,11 @@ using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
using Moq;
|
||||
|
||||
using Tgstation.Server.Api;
|
||||
using Tgstation.Server.Api.Models;
|
||||
using Tgstation.Server.Api.Models.Request;
|
||||
using Tgstation.Server.Client;
|
||||
using Tgstation.Server.Client.Components;
|
||||
using Tgstation.Server.Common.Extensions;
|
||||
using Tgstation.Server.Host.Components.Byond;
|
||||
using Tgstation.Server.Host.Configuration;
|
||||
using Tgstation.Server.Host.IO;
|
||||
|
||||
@@ -24,6 +24,7 @@ using Tgstation.Server.Api.Models.Request;
|
||||
using Tgstation.Server.Api.Models.Response;
|
||||
using Tgstation.Server.Client;
|
||||
using Tgstation.Server.Client.Components;
|
||||
using Tgstation.Server.Common.Extensions;
|
||||
using Tgstation.Server.Host.Components;
|
||||
using Tgstation.Server.Host.Components.Chat;
|
||||
using Tgstation.Server.Host.Components.Interop;
|
||||
|
||||
@@ -14,6 +14,7 @@ using Tgstation.Server.Api;
|
||||
using Tgstation.Server.Api.Models;
|
||||
using Tgstation.Server.Api.Models.Response;
|
||||
using Tgstation.Server.Client;
|
||||
using Tgstation.Server.Common.Extensions;
|
||||
using Tgstation.Server.Host;
|
||||
|
||||
namespace Tgstation.Server.Tests.Live
|
||||
|
||||
@@ -31,6 +31,7 @@ using Tgstation.Server.Api.Models.Response;
|
||||
using Tgstation.Server.Api.Rights;
|
||||
using Tgstation.Server.Client;
|
||||
using Tgstation.Server.Client.Components;
|
||||
using Tgstation.Server.Common.Extensions;
|
||||
using Tgstation.Server.Host.Components;
|
||||
using Tgstation.Server.Host.Configuration;
|
||||
using Tgstation.Server.Host.Database;
|
||||
|
||||
@@ -9,6 +9,7 @@ using System.Xml.Linq;
|
||||
|
||||
using Tgstation.Server.Api;
|
||||
using Tgstation.Server.Client;
|
||||
using Tgstation.Server.Common.Extensions;
|
||||
using Tgstation.Server.Host;
|
||||
using Tgstation.Server.Host.Components.Interop;
|
||||
using Tgstation.Server.Host.Configuration;
|
||||
|
||||
@@ -15,6 +15,7 @@ using Tgstation.Server.Api.Models;
|
||||
using Tgstation.Server.Api.Models.Internal;
|
||||
using Tgstation.Server.Api.Models.Request;
|
||||
using Tgstation.Server.Client;
|
||||
using Tgstation.Server.Common.Extensions;
|
||||
|
||||
static class Program
|
||||
{
|
||||
|
||||
@@ -21,6 +21,7 @@ using Octokit;
|
||||
|
||||
using Tgstation.Server.Api;
|
||||
using Tgstation.Server.Client;
|
||||
using Tgstation.Server.Common.Extensions;
|
||||
using Tgstation.Server.Common.Http;
|
||||
using Tgstation.Server.Host.Common;
|
||||
using Tgstation.Server.Host.IO;
|
||||
|
||||
Reference in New Issue
Block a user