mirror of
https://github.com/tgstation/tgstation-server.git
synced 2026-08-27 07:04:57 +01:00
Merge pull request #529 from tgstation/revert-518-MoreStuff
Revert "Some watchdog stuff I forgot to merge then went looking for"
This commit is contained in:
@@ -41,8 +41,6 @@ test_script:
|
||||
- ps: $wc = New-Object 'System.Net.WebClient'
|
||||
- ps: $wc.UploadFile("https://ci.appveyor.com/api/testresults/mstest/$($env:APPVEYOR_JOB_ID)", (Resolve-Path .\TestResults\results.trx))
|
||||
- vstest.console /logger:trx;LogFileName=results.trx "tests\Tgstation.Server.Host.Tests\bin\%CONFIGURATION%\netcoreapp2.0\Tgstation.Server.Host.Tests.dll" /Enablecodecoverage /inIsolation /Platform:x64
|
||||
- ps: $wc = New-Object 'System.Net.WebClient'
|
||||
- ps: $wc.UploadFile("https://ci.appveyor.com/api/testresults/mstest/$($env:APPVEYOR_JOB_ID)", (Resolve-Path .\TestResults\results.trx))
|
||||
- vstest.console /logger:trx;LogFileName=results.trx "tests\Tgstation.Server.Host.Console.Tests\bin\%CONFIGURATION%\netcoreapp2.0\Tgstation.Server.Host.Console.Tests.dll" /Enablecodecoverage /inIsolation /Platform:x64
|
||||
- ps: $wc = New-Object 'System.Net.WebClient'
|
||||
- ps: $wc.UploadFile("https://ci.appveyor.com/api/testresults/mstest/$($env:APPVEYOR_JOB_ID)", (Resolve-Path .\TestResults\results.trx))
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Tgstation.Server.Api.Rights;
|
||||
using Tgstation.Server.Api.Rights;
|
||||
|
||||
namespace Tgstation.Server.Api.Models.Internal
|
||||
{
|
||||
@@ -13,28 +12,24 @@ namespace Tgstation.Server.Api.Models.Internal
|
||||
/// If the BYOND web client can be used to connect to the game server
|
||||
/// </summary>
|
||||
[Permissions(ReadRight = DreamDaemonRights.ReadMetadata, WriteRight = DreamDaemonRights.SetWebClient)]
|
||||
[Required]
|
||||
public bool? AllowWebClient { get; set; }
|
||||
public bool AllowWebClient { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="DreamDaemonSecurity"/> level of <see cref="DreamDaemon"/>
|
||||
/// </summary>
|
||||
[Permissions(ReadRight = DreamDaemonRights.ReadMetadata, WriteRight = DreamDaemonRights.SetSecurity)]
|
||||
[Required]
|
||||
public DreamDaemonSecurity? SecurityLevel { get; set; }
|
||||
public DreamDaemonSecurity SecurityLevel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The first port <see cref="DreamDaemon"/> uses. This should be the publically advertised port
|
||||
/// </summary>
|
||||
[Permissions(ReadRight = DreamDaemonRights.ReadMetadata, WriteRight = DreamDaemonRights.SetPorts)]
|
||||
[Required]
|
||||
public ushort? PrimaryPort { get; set; }
|
||||
public ushort PrimaryPort { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The second port <see cref="DreamDaemon"/> uses
|
||||
/// </summary>
|
||||
[Permissions(ReadRight = DreamDaemonRights.ReadMetadata, WriteRight = DreamDaemonRights.SetPorts)]
|
||||
[Required]
|
||||
public ushort? SecondaryPort { get; set; }
|
||||
public ushort SecondaryPort { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Tgstation.Server.Api.Rights;
|
||||
using Tgstation.Server.Api.Rights;
|
||||
|
||||
namespace Tgstation.Server.Api.Models.Internal
|
||||
{
|
||||
@@ -12,21 +11,18 @@ namespace Tgstation.Server.Api.Models.Internal
|
||||
/// If <see cref="DreamDaemon"/> starts when it's <see cref="Instance"/> starts
|
||||
/// </summary>
|
||||
[Permissions(ReadRight = DreamDaemonRights.ReadMetadata, WriteRight = DreamDaemonRights.SetAutoStart)]
|
||||
[Required]
|
||||
public bool? AutoStart { get; set; }
|
||||
public bool AutoStart { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If the server is undergoing a soft reset. This may be automatically set by changes to other fields
|
||||
/// </summary>
|
||||
[Permissions(ReadRight = DreamDaemonRights.ReadMetadata, WriteRight = DreamDaemonRights.SoftRestart)]
|
||||
[Required]
|
||||
public bool? SoftRestart { get; set; }
|
||||
public bool SoftRestart { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If the server is undergoing a soft shutdown
|
||||
/// </summary>
|
||||
[Permissions(ReadRight = DreamDaemonRights.ReadMetadata, WriteRight = DreamDaemonRights.SoftShutdown)]
|
||||
[Required]
|
||||
public bool? SoftShutdown { get; set; }
|
||||
public bool SoftShutdown { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,12 +27,6 @@ namespace Tgstation.Server.Host.Components
|
||||
/// <inheritdoc />
|
||||
public bool SoftStopping { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public DreamDaemonLaunchParameters LastLaunchParameters { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Host.Models.CompileJob LastCompileJob => watchdog.CurrentCompileJob;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IEventConsumer"/> for <see cref="DreamDaemon"/>
|
||||
/// </summary>
|
||||
@@ -75,7 +69,7 @@ namespace Tgstation.Server.Host.Components
|
||||
this.watchdog = watchdog ?? throw new ArgumentNullException(nameof(watchdog));
|
||||
currentLaunchParameters = initialSettings ?? throw new ArgumentNullException(nameof(initialSettings));
|
||||
|
||||
autoStart = initialSettings.AutoStart.Value;
|
||||
autoStart = initialSettings.AutoStart;
|
||||
|
||||
semaphore = new SemaphoreSlim(1);
|
||||
}
|
||||
@@ -204,7 +198,6 @@ namespace Tgstation.Server.Host.Components
|
||||
await semaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
LastLaunchParameters = currentLaunchParameters;
|
||||
return currentLaunchParameters;
|
||||
}
|
||||
finally
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace Tgstation.Server.Host.Components
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<int> RunDreamDaemon(DreamDaemonLaunchParameters launchParameters, TaskCompletionSource<object> onSuccessfulStartup, string dreamDaemonPath, IDmbProvider dmbProvider, InteropInfo interopInfo, bool alwaysKill, bool asDefaultOtherServer, CancellationToken cancellationToken)
|
||||
public async Task<int> RunDreamDaemon(DreamDaemonLaunchParameters launchParameters, TaskCompletionSource<object> onSuccessfulStartup, string dreamDaemonPath, IDmbProvider dmbProvider, InteropInfo interopInfo, bool alwaysKill, CancellationToken cancellationToken)
|
||||
{
|
||||
if (launchParameters == null)
|
||||
throw new ArgumentNullException(nameof(launchParameters));
|
||||
@@ -86,9 +86,9 @@ namespace Tgstation.Server.Host.Components
|
||||
|
||||
proc.StartInfo.Arguments = String.Format(CultureInfo.InvariantCulture, "{0} -port {1} {2}-close -{3} -verbose -public -params \"{4}={5}&{6}={7}\"",
|
||||
dmbProvider.DmbName,
|
||||
isPrimary && !asDefaultOtherServer ? launchParameters.PrimaryPort : launchParameters.SecondaryPort,
|
||||
launchParameters.AllowWebClient.Value ? "-webclient " : String.Empty,
|
||||
SecurityWord(launchParameters.SecurityLevel.Value),
|
||||
isPrimary ? launchParameters.PrimaryPort : launchParameters.SecondaryPort,
|
||||
launchParameters.AllowWebClient ? "-webclient " : String.Empty,
|
||||
SecurityWord(launchParameters.SecurityLevel),
|
||||
DreamDaemonParameters.HostVersion, Application.Version,
|
||||
DreamDaemonParameters.InfoJsonPath, jsonPath);
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ namespace Tgstation.Server.Host.Components
|
||||
};
|
||||
|
||||
using (var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken))
|
||||
using (var control = interop.CreateRun(launchParameters.PrimaryPort.Value, null, null))
|
||||
using (var control = interop.CreateRun(launchParameters.PrimaryPort, null, null))
|
||||
{
|
||||
var interopInfo = new InteropInfo
|
||||
{
|
||||
@@ -113,7 +113,7 @@ namespace Tgstation.Server.Host.Components
|
||||
ddTcs.SetResult(null);
|
||||
};
|
||||
var dirA = ioManager.ConcatPath(job.DirectoryName.ToString(), ADirectoryName);
|
||||
var ddTestTask = dreamDaemonExecutor.RunDreamDaemon(launchParameters, null, dreamDaemonPath, new TemporaryDmbProvider(ioManager.ResolvePath(ioManager.GetDirectoryName(dirA)), ioManager.ResolvePath(ioManager.ConcatPath(dirA, String.Concat(job.DmeName, DmbExtension)))), interopInfo, true, false, cts.Token);
|
||||
var ddTestTask = dreamDaemonExecutor.RunDreamDaemon(launchParameters, null, dreamDaemonPath, new TemporaryDmbProvider(ioManager.ResolvePath(ioManager.GetDirectoryName(dirA)), ioManager.ResolvePath(ioManager.ConcatPath(dirA, String.Concat(job.DmeName, DmbExtension)))), interopInfo, true, cts.Token);
|
||||
|
||||
await Task.WhenAny(ddTcs.Task, ddTestTask).ConfigureAwait(false);
|
||||
|
||||
|
||||
@@ -22,10 +22,10 @@ namespace Tgstation.Server.Host.Components
|
||||
/// The secondary game directory with a trailing directory separator
|
||||
/// </summary>
|
||||
string SecondaryDirectory { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="CompileJob"/> of the .dmb
|
||||
/// The <see cref="Host.Models.RevisionInformation"/> of the .dmb
|
||||
/// </summary>
|
||||
CompileJob CompileJob { get; }
|
||||
RevisionInformation RevisionInformation { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,16 +41,6 @@ namespace Tgstation.Server.Host.Components
|
||||
/// </summary>
|
||||
string AccessToken { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="DreamDaemonLaunchParameters"/> most recently used
|
||||
/// </summary>
|
||||
DreamDaemonLaunchParameters LastLaunchParameters { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="Host.Models.CompileJob"/> most recently used
|
||||
/// </summary>
|
||||
Host.Models.CompileJob LastCompileJob { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Launch DreamDaemon
|
||||
/// </summary>
|
||||
|
||||
@@ -19,9 +19,8 @@ namespace Tgstation.Server.Host.Components
|
||||
/// <param name="dmbProvider">The <see cref="IDmbProvider"/> for the .dmb to run</param>
|
||||
/// <param name="interopInfo">The <see cref="InteropInfo"/> for the run</param>
|
||||
/// <param name="alwaysKill">If the resulting process should never be left alive</param>
|
||||
/// <param name="asDefaultOtherServer">If <see langword="true"/> the ports will be swapped for the launch</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
|
||||
/// <returns>A <see cref="Task{TResult}"/> representing the lifetime of the process and resulting in the exit code</returns>
|
||||
Task<int> RunDreamDaemon(DreamDaemonLaunchParameters launchParameters, TaskCompletionSource<object> onSuccessfulStartup, string dreamDaemonPath, IDmbProvider dmbProvider, InteropInfo interopInfo, bool alwaysKill, bool asDefaultOtherServer, CancellationToken cancellationToken);
|
||||
Task<int> RunDreamDaemon(DreamDaemonLaunchParameters launchParameters, TaskCompletionSource<object> onSuccessfulStartup, string dreamDaemonPath, IDmbProvider dmbProvider, InteropInfo interopInfo, bool alwaysKill, CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,5 @@ namespace Tgstation.Server.Host.Components
|
||||
Task ActivateOtherServer(CancellationToken cancellationToken);
|
||||
|
||||
Task ChangePort(ushort newPort, bool forPrimary, CancellationToken cancellationToken);
|
||||
|
||||
void OnNextSwap(Action action);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,11 +8,6 @@ namespace Tgstation.Server.Host.Components
|
||||
/// </summary>
|
||||
interface IWatchdog
|
||||
{
|
||||
/// <summary>
|
||||
/// The latest <see cref="Host.Models.CompileJob"/> used by the <see cref="IWatchdog"/>
|
||||
/// </summary>
|
||||
Host.Models.CompileJob CurrentCompileJob { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Start the <see cref="IWatchdog"/>
|
||||
/// </summary>
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Tgstation.Server.Host.Components
|
||||
public string SecondaryDirectory => throw new NotSupportedException();
|
||||
|
||||
/// <inheritdoc />
|
||||
public CompileJob CompileJob => null;
|
||||
public RevisionInformation RevisionInformation => null;
|
||||
|
||||
/// <summary>
|
||||
/// Construct a <see cref="TemporaryDmbProvider"/>
|
||||
|
||||
@@ -10,9 +10,6 @@ namespace Tgstation.Server.Host.Components
|
||||
/// <inheritdoc />
|
||||
sealed class Watchdog : IWatchdog, IDisposable
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public Host.Models.CompileJob CurrentCompileJob { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IByond"/> for the <see cref="Watchdog"/>
|
||||
/// </summary>
|
||||
@@ -88,26 +85,13 @@ namespace Tgstation.Server.Host.Components
|
||||
/// <param name="launchParameters">The <see cref="DreamDaemonLaunchParameters"/> for the run</param>
|
||||
/// <param name="onSuccessfulStartup">The <see cref="TaskCompletionSource{TResult}"/> to be completed once the server starts if any</param>
|
||||
/// <param name="interopInfo">The <see cref="InteropInfo"/> the server</param>
|
||||
/// <param name="control">The <see cref="IInteropControl"/> for the operation</param>
|
||||
/// <param name="dreamDaemonPath">The path to the DreamDaemon executable</param>
|
||||
/// <param name="asDefaultOtherServer">If the ports should be swapped</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
|
||||
/// <returns>A <see cref="Task{TResult}"/> resulting in the exit code of DreamDaemon</returns>
|
||||
async Task<int> RunServer(DreamDaemonLaunchParameters launchParameters, TaskCompletionSource<object> onSuccessfulStartup, InteropInfo interopInfo, IInteropControl control, string dreamDaemonPath, bool asDefaultOtherServer, CancellationToken cancellationToken)
|
||||
async Task<int> RunServer(DreamDaemonLaunchParameters launchParameters, TaskCompletionSource<object> onSuccessfulStartup, InteropInfo interopInfo, string dreamDaemonPath, CancellationToken cancellationToken)
|
||||
{
|
||||
using (var dmb = await dmbFactory.LockNextDmb(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
void OnBecomingCurrentServer() => CurrentCompileJob = dmb.CompileJob;
|
||||
|
||||
var runningNow = launchParameters.SecondaryPort == interopInfo.NextPort;
|
||||
if (asDefaultOtherServer)
|
||||
runningNow = !runningNow;
|
||||
|
||||
if (runningNow)
|
||||
OnBecomingCurrentServer();
|
||||
else
|
||||
control.OnNextSwap(OnBecomingCurrentServer);
|
||||
|
||||
var chatJsonGuid = Guid.NewGuid();
|
||||
var isPrimary = interopInfo.NextPort == launchParameters.SecondaryPort;
|
||||
|
||||
@@ -118,8 +102,8 @@ namespace Tgstation.Server.Host.Components
|
||||
interopInfo.ChatCommandsJson = String.Concat(chatJsonGuid, ".commands.json");
|
||||
|
||||
//set up revision
|
||||
interopInfo.Revision = dmb.CompileJob.RevisionInformation;
|
||||
foreach (var I in dmb.CompileJob.RevisionInformation.TestMerges)
|
||||
interopInfo.Revision = dmb.RevisionInformation;
|
||||
foreach (var I in dmb.RevisionInformation.TestMerges)
|
||||
interopInfo.TestMerges.Add(new Models.TestMerge
|
||||
{
|
||||
Author = I.Author,
|
||||
@@ -135,22 +119,21 @@ namespace Tgstation.Server.Host.Components
|
||||
});
|
||||
|
||||
using (await chat.TrackJsons(isPrimary ? dmb.PrimaryDirectory : dmb.SecondaryDirectory, interopInfo.ChatChannelsJson, isPrimary ? interopInfo.ChatCommandsJson : null, cancellationToken).ConfigureAwait(false))
|
||||
return await dreamDaemonExecutor.RunDreamDaemon(launchParameters, onSuccessfulStartup, dreamDaemonPath, dmb, interopInfo, false, asDefaultOtherServer, cancellationToken).ConfigureAwait(false);
|
||||
return await dreamDaemonExecutor.RunDreamDaemon(launchParameters, onSuccessfulStartup, dreamDaemonPath, dmb, interopInfo, false, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Locks in a <see cref="IByond"/> version and runs a server through <see cref="RunServer"/>
|
||||
/// Locks in a <see cref="IByond"/> version and runs a server through <see cref="RunServer(DreamDaemonLaunchParameters, TaskCompletionSource{object}, InteropInfo, string, CancellationToken)"/>
|
||||
/// </summary>
|
||||
/// <param name="launchParameters">The <see cref="DreamDaemonLaunchParameters"/> for the run</param>
|
||||
/// <param name="onSuccessfulStartup">The <see cref="TaskCompletionSource{TResult}"/> to be completed once the server starts if any</param>
|
||||
/// <param name="control">The <see cref="IInteropControl"/> for the operation</param>
|
||||
/// <param name="accessToken">The access token for the server</param>
|
||||
/// <param name="isPrimary">If a primary server is being launched</param>
|
||||
/// <param name="isDefaultOther">If the ports should be swapped</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
|
||||
/// <param name="cancellationTokenSource">A <see cref="CancellationTokenSource"/> tied to the lifetime of the resulting <see cref="Task{TResult}"/></param>
|
||||
/// <returns>A <see cref="Task{TResult}"/> resulting in the exit code of DreamDaemon</returns>
|
||||
Task<int> StartServer(DreamDaemonLaunchParameters launchParameters, TaskCompletionSource<object> onSuccessfulStartup, IInteropControl control, bool isPrimary, bool isDefaultOther, CancellationToken cancellationToken, out CancellationTokenSource cancellationTokenSource)
|
||||
Task<int> StartServer(DreamDaemonLaunchParameters launchParameters, TaskCompletionSource<object> onSuccessfulStartup, string accessToken, bool isPrimary, CancellationToken cancellationToken, out CancellationTokenSource cancellationTokenSource)
|
||||
{
|
||||
cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
|
||||
try
|
||||
@@ -159,16 +142,16 @@ namespace Tgstation.Server.Host.Components
|
||||
|
||||
var interopInfo = new InteropInfo
|
||||
{
|
||||
AccessToken = isPrimary ? control.PrimaryAccessToken : control.SecondaryAccessToken,
|
||||
AccessToken = accessToken,
|
||||
ApiValidateOnly = false,
|
||||
HostPath = Application.HostingPath,
|
||||
InstanceId = instanceId,
|
||||
NextPort = isPrimary ? launchParameters.SecondaryPort.Value : launchParameters.PrimaryPort.Value,
|
||||
NextPort = isPrimary ? launchParameters.SecondaryPort : launchParameters.PrimaryPort,
|
||||
//this line feels hacky, change it and remove the instanceManager dep?
|
||||
InstanceName = instanceManager.GetInstance(new Host.Models.Instance { Id = instanceId }).GetMetadata().Name,
|
||||
};
|
||||
|
||||
return byond.UseExecutables((dreamMakerPath, dreamDaemonPath) => RunServer(launchParameters, onSuccessfulStartup, interopInfo, control, dreamDaemonPath, isDefaultOther, ddToken), false);
|
||||
return byond.UseExecutables((dreamMakerPath, dreamDaemonPath) => RunServer(launchParameters, onSuccessfulStartup, interopInfo, dreamDaemonPath, ddToken), false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -233,7 +216,7 @@ namespace Tgstation.Server.Host.Components
|
||||
var retryDelay = (int)Math.Min(Math.Pow(2, retries), TimeSpan.FromHours(1).Milliseconds); //max of one hour
|
||||
await Task.Delay(retryDelay, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
using (var control = interop.CreateRun(initialLaunchParameters.PrimaryPort.Value, initialLaunchParameters.SecondaryPort.Value, HandleChatMessage))
|
||||
using (var control = interop.CreateRun(initialLaunchParameters.PrimaryPort, initialLaunchParameters.SecondaryPort, HandleChatMessage))
|
||||
{
|
||||
var primaryPrimedTcs = new TaskCompletionSource<object>();
|
||||
control.OnServerControl += (sender, e) =>
|
||||
@@ -243,7 +226,7 @@ namespace Tgstation.Server.Host.Components
|
||||
};
|
||||
|
||||
//start the primary server
|
||||
var ddPrimaryTask = StartServer(initialLaunchParameters, onSuccessfulStartup, control, true, false, cancellationToken, out CancellationTokenSource primaryCts);
|
||||
var ddPrimaryTask = StartServer(initialLaunchParameters, onSuccessfulStartup, control.PrimaryAccessToken, true, cancellationToken, out CancellationTokenSource primaryCts);
|
||||
try
|
||||
{
|
||||
//wait to make sure we got this far
|
||||
@@ -270,7 +253,7 @@ namespace Tgstation.Server.Host.Components
|
||||
{
|
||||
if (ddSecondaryTask == null)
|
||||
//start the secondary server
|
||||
ddSecondaryTask = StartServer(initialLaunchParameters, null, control, false, false, cancellationToken, out secondaryCts);
|
||||
ddSecondaryTask = StartServer(initialLaunchParameters, null, control.SecondaryAccessToken, false, cancellationToken, out secondaryCts);
|
||||
|
||||
var newDmbTask = dmbFactory.OnNewerDmb();
|
||||
|
||||
@@ -281,7 +264,7 @@ namespace Tgstation.Server.Host.Components
|
||||
void PrimaryRestart()
|
||||
{
|
||||
primaryCts.Dispose();
|
||||
ddPrimaryTask = StartServer(initialLaunchParameters, null, control, true, true, cancellationToken, out primaryCts);
|
||||
ddPrimaryTask = StartServer(initialLaunchParameters, null, control.PrimaryAccessToken, true, cancellationToken, out primaryCts);
|
||||
}
|
||||
void SecondaryRestart()
|
||||
{
|
||||
|
||||
@@ -1,164 +0,0 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Net;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Tgstation.Server.Api.Models;
|
||||
using Tgstation.Server.Api.Models.Internal;
|
||||
using Tgstation.Server.Api.Rights;
|
||||
using Tgstation.Server.Host.Components;
|
||||
using Tgstation.Server.Host.Core;
|
||||
using Tgstation.Server.Host.Models;
|
||||
using Tgstation.Server.Host.Security;
|
||||
|
||||
namespace Tgstation.Server.Host.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// <see cref="ModelController{TModel}"/> for managing <see cref="Api.Models.DreamDaemon"/>
|
||||
/// </summary>
|
||||
[Route("/" + nameof(Api.Models.DreamDaemon))]
|
||||
public sealed class DreamDaemonController : ModelController<Api.Models.DreamDaemon>
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="IJobManager"/> for the <see cref="DreamMakerController"/>
|
||||
/// </summary>
|
||||
readonly IJobManager jobManager;
|
||||
/// <summary>
|
||||
/// The <see cref="IInstanceManager"/> for the <see cref="DreamMakerController"/>
|
||||
/// </summary>
|
||||
readonly IInstanceManager instanceManager;
|
||||
|
||||
/// <summary>
|
||||
/// Construct a <see cref="DreamDaemonController"/>
|
||||
/// </summary>
|
||||
/// <param name="databaseContext">The <see cref="IDatabaseContext"/> for the <see cref="ApiController"/></param>
|
||||
/// <param name="authenticationContextFactory">The <see cref="IAuthenticationContextFactory"/> for the <see cref="ApiController"/></param>
|
||||
/// <param name="jobManager">The value of <see cref="jobManager"/></param>
|
||||
/// <param name="instanceManager">The value of <see cref="instanceManager"/></param>
|
||||
public DreamDaemonController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, IJobManager jobManager, IInstanceManager instanceManager) : base(databaseContext, authenticationContextFactory)
|
||||
{
|
||||
this.jobManager = jobManager ?? throw new ArgumentNullException(nameof(jobManager));
|
||||
this.instanceManager = instanceManager ?? throw new ArgumentNullException(nameof(instanceManager));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[TgsAuthorize(DreamDaemonRights.Start)]
|
||||
public override async Task<IActionResult> Create([FromBody] Api.Models.DreamDaemon model, CancellationToken cancellationToken)
|
||||
{
|
||||
var instance = instanceManager.GetInstance(Instance);
|
||||
|
||||
if (instance.DreamDaemon.Running)
|
||||
return StatusCode(HttpStatusCode.Gone);
|
||||
|
||||
var launchParams = await DatabaseContext.Instances.Where(x => x.Id == Instance.Id).Select(x => new DreamDaemonLaunchParameters
|
||||
{
|
||||
AllowWebClient = x.DreamDaemonSettings.AllowWebClient,
|
||||
PrimaryPort = x.DreamDaemonSettings.PrimaryPort,
|
||||
SecondaryPort = x.DreamDaemonSettings.SecondaryPort,
|
||||
SecurityLevel = x.DreamDaemonSettings.SecurityLevel
|
||||
}).FirstAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
await jobManager.RegisterOperation(new Models.Job
|
||||
{
|
||||
Description = "Launch DreamDaemon",
|
||||
CancelRight = (int)DreamDaemonRights.Shutdown,
|
||||
CancelRightsType = RightsType.DreamDaemon,
|
||||
Instance = Instance,
|
||||
StartedBy = AuthenticationContext.User
|
||||
}, (job, serviceProvider, innerCt) => instance.DreamDaemon.Launch(launchParams, innerCt), cancellationToken).ConfigureAwait(false);
|
||||
return Ok();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[TgsAuthorize(DreamDaemonRights.ReadMetadata | DreamDaemonRights.ReadRevision)]
|
||||
public override async Task<IActionResult> Read(CancellationToken cancellationToken)
|
||||
{
|
||||
var dd = instanceManager.GetInstance(Instance).DreamDaemon;
|
||||
|
||||
var metadata = (AuthenticationContext.GetRight(RightsType.DreamDaemon) & (int)DreamDaemonRights.ReadMetadata) != 0;
|
||||
var revision = (AuthenticationContext.GetRight(RightsType.DreamDaemon) & (int)DreamDaemonRights.ReadRevision) != 0;
|
||||
|
||||
var settings = metadata ? await DatabaseContext.Instances.Where(x => x.Id == Instance.Id).Select(x => x.DreamDaemonSettings).FirstAsync(cancellationToken).ConfigureAwait(false) : null;
|
||||
Api.Models.DreamDaemon result = new Api.Models.DreamDaemon();
|
||||
if(metadata)
|
||||
{
|
||||
result.AutoStart = settings.AutoStart;
|
||||
result.CurrentPort = dd.CurrentPort;
|
||||
result.CurrentSecurity = dd.CurrentSecurity;
|
||||
result.PrimaryPort = dd.LastLaunchParameters.PrimaryPort;
|
||||
result.AllowWebClient = dd.LastLaunchParameters.AllowWebClient;
|
||||
result.Running = dd.Running;
|
||||
result.SecondaryPort = dd.LastLaunchParameters.SecondaryPort;
|
||||
result.SecurityLevel = dd.LastLaunchParameters.SecurityLevel;
|
||||
result.SoftRestart = dd.SoftRebooting;
|
||||
result.SoftShutdown = dd.SoftStopping;
|
||||
};
|
||||
if (revision)
|
||||
result.CompileJob = dd.LastCompileJob.ToApi();
|
||||
|
||||
return Json(result);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[TgsAuthorize(DreamDaemonRights.Shutdown)]
|
||||
public override async Task<IActionResult> Delete([FromBody] Api.Models.DreamDaemon model, CancellationToken cancellationToken)
|
||||
{
|
||||
var instance = instanceManager.GetInstance(Instance);
|
||||
|
||||
if (!instance.DreamDaemon.Running)
|
||||
return StatusCode(HttpStatusCode.Gone);
|
||||
|
||||
await instance.DreamDaemon.Terminate(false, cancellationToken).ConfigureAwait(false);
|
||||
return Ok();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[TgsAuthorize(DreamDaemonRights.SetAutoStart | DreamDaemonRights.SetPorts | DreamDaemonRights.SetSecurity | DreamDaemonRights.SetWebClient | DreamDaemonRights.SoftRestart | DreamDaemonRights.SoftShutdown | DreamDaemonRights.Start)]
|
||||
public override async Task<IActionResult> Update([FromBody] Api.Models.DreamDaemon model, CancellationToken cancellationToken)
|
||||
{
|
||||
var current = await DatabaseContext.Instances.Where(x => x.Id == Instance.Id).Select(x => x.DreamDaemonSettings).FirstAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var userRights = (DreamDaemonRights)AuthenticationContext.GetRight(RightsType.DreamDaemon);
|
||||
|
||||
bool CheckModified<T>(Expression<Func<Api.Models.Internal.DreamDaemonSettings, T>> expression, DreamDaemonRights requiredRight)
|
||||
{
|
||||
var memberSelectorExpression = (MemberExpression)expression.Body;
|
||||
var property = (PropertyInfo)memberSelectorExpression.Member;
|
||||
|
||||
var newVal = property.GetValue(model);
|
||||
if (newVal == null)
|
||||
return false;
|
||||
if (!userRights.HasFlag(requiredRight) && property.GetValue(current) != newVal)
|
||||
return true;
|
||||
|
||||
property.SetValue(current, newVal);
|
||||
return false;
|
||||
};
|
||||
|
||||
if (!CheckModified(x => x.AllowWebClient, DreamDaemonRights.SetWebClient)
|
||||
|| !CheckModified(x => x.AutoStart, DreamDaemonRights.SetAutoStart)
|
||||
|| !CheckModified(x => x.PrimaryPort, DreamDaemonRights.SetPorts)
|
||||
|| !CheckModified(x => x.SecondaryPort, DreamDaemonRights.SetPorts)
|
||||
|| !CheckModified(x => x.SecurityLevel, DreamDaemonRights.SetSecurity)
|
||||
|| !CheckModified(x => x.SoftRestart, DreamDaemonRights.SoftRestart))
|
||||
return Forbid();
|
||||
|
||||
//interaction with soft stop is a bit different
|
||||
if (model.SoftShutdown.HasValue)
|
||||
{
|
||||
if (current.SoftShutdown != model.SoftShutdown && ((!current.SoftShutdown.Value && !userRights.HasFlag(DreamDaemonRights.SoftShutdown)) || (current.SoftShutdown.Value && !userRights.HasFlag(DreamDaemonRights.Start))))
|
||||
return Forbid();
|
||||
current.SoftShutdown = model.SoftShutdown;
|
||||
}
|
||||
|
||||
await instanceManager.GetInstance(Instance).DreamDaemon.ChangeSettings(current, cancellationToken).ConfigureAwait(false);
|
||||
await DatabaseContext.Save(default).ConfigureAwait(false);
|
||||
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
/// <summary>
|
||||
/// Controller for managing the compiler
|
||||
/// </summary>
|
||||
[Route("/" + nameof(DreamMaker))]
|
||||
[Route("/DreamMaker")]
|
||||
public sealed class DreamMakerController : ModelController<Api.Models.DreamMaker>
|
||||
{
|
||||
/// <summary>
|
||||
@@ -30,7 +30,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
readonly IInstanceManager instanceManager;
|
||||
|
||||
/// <summary>
|
||||
/// Construct a <see cref="DreamMakerController"/>
|
||||
/// Construct a <see cref="HomeController"/>
|
||||
/// </summary>
|
||||
/// <param name="databaseContext">The <see cref="IDatabaseContext"/> for the <see cref="ApiController"/></param>
|
||||
/// <param name="authenticationContextFactory">The <see cref="IAuthenticationContextFactory"/> for the <see cref="ApiController"/></param>
|
||||
@@ -66,8 +66,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
Description = "Compile active repository code",
|
||||
StartedBy = AuthenticationContext.User,
|
||||
CancelRightsType = RightsType.DreamMaker,
|
||||
CancelRight = (int)DreamMakerRights.CancelCompile,
|
||||
Instance = Instance
|
||||
CancelRight = (int)DreamMakerRights.CancelCompile
|
||||
};
|
||||
await jobManager.RegisterOperation(job, (paramJob, serviceProvider, ct) => RunCompile(paramJob, serviceProvider, Instance, ct), cancellationToken).ConfigureAwait(false);
|
||||
return Json(job);
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
/// <summary>
|
||||
/// <see cref="ModelController{TModel}"/> for <see cref="Api.Models.Job"/>s
|
||||
/// </summary>
|
||||
[Route("/" + nameof(Job))]
|
||||
[Route("/Job")]
|
||||
public sealed class JobController : ModelController<Api.Models.Job>
|
||||
{
|
||||
/// <summary>
|
||||
@@ -60,24 +60,11 @@ namespace Tgstation.Server.Host.Controllers
|
||||
if (job == default(Job))
|
||||
return NotFound();
|
||||
|
||||
if (job.CancelRight.HasValue && job.CancelRightsType.HasValue && (AuthenticationContext.GetRight(job.CancelRightsType.Value) & job.CancelRight.Value) == 0)
|
||||
return Forbid();
|
||||
|
||||
if(job.StoppedAt != null)
|
||||
return StatusCode(HttpStatusCode.Gone);
|
||||
|
||||
await jobManager.CancelJob(job, AuthenticationContext.User, cancellationToken).ConfigureAwait(false);
|
||||
return Ok();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[TgsAuthorize]
|
||||
public override async Task<IActionResult> GetId(long id, CancellationToken cancellationToken)
|
||||
{
|
||||
var job = await DatabaseContext.Jobs.Where(x => x.Id == id).Include(x => x.StartedBy).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
|
||||
if (job == default(Job))
|
||||
return NotFound();
|
||||
return Json(job.ToApi());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,15 +43,6 @@ namespace Tgstation.Server.Host.Controllers
|
||||
[HttpGet]
|
||||
public virtual Task<IActionResult> Read(CancellationToken cancellationToken) => Task.FromResult((IActionResult)NotFound());
|
||||
|
||||
/// <summary>
|
||||
/// Attempt to get a specific a <typeparamref name="TModel"/>
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
|
||||
/// <param name="id">The ID of the model to get</param>
|
||||
/// <returns>A <see cref="Task{TResult}"/> resulting in the <see cref="IActionResult"/> of the operation</returns>
|
||||
[HttpGet("/{0}")]
|
||||
public virtual Task<IActionResult> GetId(long id, CancellationToken cancellationToken) => Task.FromResult((IActionResult)NotFound());
|
||||
|
||||
/// <summary>
|
||||
/// Attempt to update a <paramref name="model"/>
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user