mirror of
https://github.com/tgstation/tgstation-server.git
synced 2026-08-27 07:04:57 +01:00
Refactor refactor refactor some more
This commit is contained in:
@@ -18,7 +18,7 @@
|
||||
var/access_token
|
||||
var/instance_id
|
||||
var/instance_name
|
||||
var/host_port
|
||||
var/host_path
|
||||
var/port_1
|
||||
var/port_2
|
||||
var/cached_json
|
||||
@@ -50,7 +50,7 @@
|
||||
|
||||
access_token = cached_json["access_token"]
|
||||
instance_id = text2num(cached_json["instance_id"])
|
||||
host_port = text2num(cached_json["host_port"])
|
||||
host_path = cached_json["host_path"]
|
||||
if(cached_json["api_validate_only"])
|
||||
Export(TGS4_COMM_VALIDATE)
|
||||
del(world)
|
||||
@@ -110,7 +110,7 @@
|
||||
world.OpenPort(new_port)
|
||||
|
||||
/datum/tgs_api/v4/proc/Export(command)
|
||||
return world.Export("http://127.0.0.1:[host_port]/Interop/[instance_id]?command=[url_encode(command)]&access_token=[access_token]")
|
||||
return world.Export("[host_path]/Interop/[instance_id]?command=[url_encode(command)]&access_token=[access_token]")
|
||||
|
||||
/datum/tgs_api/v4/OnReboot()
|
||||
var/json = Export(TGS4_COMM_SERVER_REBOOT)
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
results[command_name] = list("help_text" = stc.help_text, "admin_only" = stc.admin_only)
|
||||
custom_commands[command_name] = stc
|
||||
|
||||
var/commands_file = cached_json["chat_commands_file"]
|
||||
var/commands_file = cached_json["chat_commands_json"]
|
||||
if(!commands_file)
|
||||
return
|
||||
text2file(json_encode(results), commands_file)
|
||||
|
||||
@@ -40,5 +40,15 @@ namespace Tgstation.Server.Api.Models
|
||||
/// </summary>
|
||||
[Permissions(WriteRight = InstanceManagerRights.SetConfiguration)]
|
||||
public bool ConfigurationAllowed { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Instance CloneMetadata() => new Instance
|
||||
{
|
||||
Id = Id,
|
||||
Name = Name,
|
||||
Path = Path,
|
||||
Online = Online,
|
||||
ConfigurationAllowed = ConfigurationAllowed
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Tgstation.Server.Api.Models.Internal
|
||||
/// </summary>
|
||||
[Permissions(DenyWrite = true)]
|
||||
[Required, StringLength(40)]
|
||||
public string Revision { get; set; }
|
||||
public string Commit { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The sha of the most recent remote commit
|
||||
|
||||
@@ -31,6 +31,12 @@ namespace Tgstation.Server.Api.Models.Internal
|
||||
[Required]
|
||||
public string BodyAtMerge { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The URL of the pull request
|
||||
/// </summary>
|
||||
[Required]
|
||||
public Uri Url { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The author of the pull request
|
||||
/// </summary>
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Tgstation.Server.Api.Models;
|
||||
using Tgstation.Server.Api.Models.Internal;
|
||||
using Tgstation.Server.Host.Components.Models;
|
||||
using Tgstation.Server.Host.Core;
|
||||
|
||||
namespace Tgstation.Server.Host.Components
|
||||
@@ -53,18 +56,41 @@ namespace Tgstation.Server.Host.Components
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<int> RunDreamDaemon(DreamDaemonLaunchParameters launchParameters, TaskCompletionSource<object> onSuccessfulStartup, string dreamDaemonPath, string dmbPath, string accessToken, bool usePrimaryPort, bool alwaysKill, 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));
|
||||
if (dreamDaemonPath == null)
|
||||
throw new ArgumentNullException(nameof(dreamDaemonPath));
|
||||
if (dmbProvider == null)
|
||||
throw new ArgumentNullException(nameof(dmbProvider));
|
||||
if (interopInfo == null)
|
||||
throw new ArgumentNullException(nameof(interopInfo));
|
||||
|
||||
if (interopInfo.NextPort != launchParameters.PrimaryPort && interopInfo.NextPort != launchParameters.SecondaryPort)
|
||||
throw new ArgumentOutOfRangeException(nameof(interopInfo), interopInfo, "interopInfo.NextPort must match primary or secondary ports!");
|
||||
|
||||
var isPrimary = interopInfo.NextPort == launchParameters.SecondaryPort;
|
||||
|
||||
//serialize the interop info to the json
|
||||
var jsonPath = String.Concat(Guid.NewGuid(), ".tgs.json");
|
||||
|
||||
var json = JsonConvert.SerializeObject(interopInfo);
|
||||
|
||||
|
||||
using (var proc = new Process())
|
||||
{
|
||||
proc.StartInfo.FileName = dreamDaemonPath;
|
||||
proc.StartInfo.WorkingDirectory = ioManager.GetDirectoryName(dmbPath);
|
||||
proc.StartInfo.Arguments = String.Format(CultureInfo.InvariantCulture, "{0} -port {1} {2}-close -{3} -verbose -public -params \"{4}={5}&{6}={7}&{8}={9}&{10}={11}&{12}={13}\"", dmbPath, usePrimaryPort ? launchParameters.PrimaryPort : launchParameters.SecondaryPort, launchParameters.AllowWebClient ? "-webclient " : String.Empty, SecurityWord(launchParameters.SecurityLevel),
|
||||
DreamDaemonParameters.AccessToken, accessToken,
|
||||
proc.StartInfo.WorkingDirectory = isPrimary ? dmbProvider.PrimaryDirectory : dmbProvider.SecondaryDirectory;
|
||||
await ioManager.WriteAllBytes(ioManager.ConcatPath(proc.StartInfo.WorkingDirectory, jsonPath), Encoding.UTF8.GetBytes(json), cancellationToken).ConfigureAwait(false);
|
||||
|
||||
proc.StartInfo.Arguments = String.Format(CultureInfo.InvariantCulture, "{0} -port {1} {2}-close -{3} -verbose -public -params \"{4}={5}&{6}={7}\"",
|
||||
dmbProvider.DmbName,
|
||||
isPrimary ? launchParameters.PrimaryPort : launchParameters.SecondaryPort,
|
||||
launchParameters.AllowWebClient ? "-webclient " : String.Empty,
|
||||
SecurityWord(launchParameters.SecurityLevel),
|
||||
DreamDaemonParameters.HostVersion, Application.Version,
|
||||
DreamDaemonParameters.IsSecondaryServer, !usePrimaryPort,
|
||||
DreamDaemonParameters.PrimaryPort, launchParameters.PrimaryPort,
|
||||
DreamDaemonParameters.SecondaryPort, launchParameters.SecondaryPort);
|
||||
DreamDaemonParameters.InfoJsonPath, jsonPath);
|
||||
|
||||
proc.EnableRaisingEvents = true;
|
||||
var tcs = new TaskCompletionSource<object>();
|
||||
@@ -85,7 +111,7 @@ namespace Tgstation.Server.Host.Components
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (!alwaysKill && !await instanceShutdownMethod.PreserveActiveExecutablesIfNecessary(launchParameters, accessToken, proc.Id, usePrimaryPort).ConfigureAwait(false))
|
||||
if (!alwaysKill && !await instanceShutdownMethod.PreserveActiveExecutablesIfNecessary(launchParameters, interopInfo.AccessToken, proc.Id, isPrimary).ConfigureAwait(false))
|
||||
{
|
||||
proc.Kill();
|
||||
proc.WaitForExit();
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
static class DreamDaemonParameters
|
||||
{
|
||||
/// <summary>
|
||||
/// Do not change to keep forwards/backwards api compatibility
|
||||
/// Host version. Do not change to keep forwards/backwards api compatibility
|
||||
/// </summary>
|
||||
public const string HostVersion = "server_service_versions";
|
||||
public const string AccessToken = "tgs_key";
|
||||
public const string PrimaryPort = "tgs_port1";
|
||||
public const string SecondaryPort = "tgs_port2";
|
||||
public const string IsSecondaryServer = "tgs_second";
|
||||
public const string HostVersion = "server_service_version";
|
||||
/// <summary>
|
||||
/// Path to <see cref="Models.InteropInfo"/> json
|
||||
/// </summary>
|
||||
public const string InfoJsonPath = "tgs_json";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -41,9 +42,11 @@ namespace Tgstation.Server.Host.Components
|
||||
/// Send a chat <paramref name="message"/> to a given set of <paramref name="channelIds"/>
|
||||
/// </summary>
|
||||
/// <param name="message">The message being sent</param>
|
||||
/// <param name="channelIds">The <see cref="Models.ChatChannel.Id"/>s of the <see cref="Models.ChatChannel"/>s to send to</param>
|
||||
/// <param name="channelIds">The <see cref="Host.Models.ChatChannel.Id"/>s of the <see cref="Host.Models.ChatChannel"/>s to send to</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
|
||||
/// <returns>A <see cref="Task"/> representing the running operation</returns>
|
||||
Task SendMessage(string message, IEnumerable<long> channelIds, CancellationToken cancellationToken);
|
||||
|
||||
Task<IDisposable> TrackJsons(string basePath, string channelsJsonName, string commandsJsonName, CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Tgstation.Server.Host.Models;
|
||||
|
||||
namespace Tgstation.Server.Host.Components
|
||||
{
|
||||
@@ -22,5 +22,10 @@ namespace Tgstation.Server.Host.Components
|
||||
/// The secondary game directory with a trailing directory separator
|
||||
/// </summary>
|
||||
string SecondaryDirectory { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="Host.Models.RevisionInformation"/> of the .dmb
|
||||
/// </summary>
|
||||
RevisionInformation RevisionInformation { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Tgstation.Server.Api.Models.Internal;
|
||||
using Tgstation.Server.Host.Components.Models;
|
||||
|
||||
namespace Tgstation.Server.Host.Components
|
||||
{
|
||||
@@ -15,12 +16,11 @@ namespace Tgstation.Server.Host.Components
|
||||
/// <param name="launchParameters">The <see cref="DreamDaemonLaunchParameters"/></param>
|
||||
/// <param name="onSuccessfulStartup">The <see cref="TaskCompletionSource{TResult}"/> that is completed when dream daemon starts without crashing</param>
|
||||
/// <param name="dreamDaemonPath">The path to the dreamdaemon executable</param>
|
||||
/// <param name="dmbPath">The path to the .dmb to run, the working directory will be derived from this</param>
|
||||
/// <param name="accessToken">The access token to be used for communication</param>
|
||||
/// <param name="usePrimaryPort">If the server should open on <see cref="DreamDaemonLaunchParameters.PrimaryPort"/> or <see cref="DreamDaemonLaunchParameters.SecondaryPort"/> of <paramref name="launchParameters"/></param>
|
||||
/// <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="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, string dmbPath, string accessToken, bool usePrimaryPort, bool alwaysKill, CancellationToken cancellationToken);
|
||||
Task<int> RunDreamDaemon(DreamDaemonLaunchParameters launchParameters, TaskCompletionSource<object> onSuccessfulStartup, string dreamDaemonPath, IDmbProvider dmbProvider, InteropInfo interopInfo, bool alwaysKill, CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@ namespace Tgstation.Server.Host.Components
|
||||
|
||||
IConfiguration Configuration { get; }
|
||||
|
||||
Api.Models.Instance GetMetadata();
|
||||
|
||||
void Rename(string newName);
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,16 @@
|
||||
|
||||
namespace Tgstation.Server.Host.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Factory for creating <see cref="IInstance"/>s
|
||||
/// </summary>
|
||||
interface IInstanceFactory
|
||||
{
|
||||
IInstance CreateInstance(Models.Instance metadata);
|
||||
/// <summary>
|
||||
/// Create an <see cref="IInstance"/>
|
||||
/// </summary>
|
||||
/// <param name="metadata">The <see cref="Host.Models.Instance"/></param>
|
||||
/// <returns>A new <see cref="IInstance"/></returns>
|
||||
IInstance CreateInstance(Host.Models.Instance metadata);
|
||||
}
|
||||
}
|
||||
@@ -11,33 +11,33 @@ namespace Tgstation.Server.Host.Components
|
||||
/// <summary>
|
||||
/// Get the <see cref="IInstance"/> associated with given <paramref name="metadata"/>
|
||||
/// </summary>
|
||||
/// <param name="metadata">The <see cref="Models.Instance"/> of the desired <see cref="IInstance"/></param>
|
||||
/// <param name="metadata">The <see cref="Host.Models.Instance"/> of the desired <see cref="IInstance"/></param>
|
||||
/// <returns>The <see cref="IInstance"/> associated with the given <paramref name="metadata"/></returns>
|
||||
IInstance GetInstance(Models.Instance metadata);
|
||||
IInstance GetInstance(Host.Models.Instance metadata);
|
||||
|
||||
/// <summary>
|
||||
/// Online an <see cref="IInstance"/>
|
||||
/// </summary>
|
||||
/// <param name="metadata">The <see cref="Models.Instance"/> of the desired <see cref="IInstance"/></param>
|
||||
/// <param name="metadata">The <see cref="Host.Models.Instance"/> of the desired <see cref="IInstance"/></param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
|
||||
/// <returns>A <see cref="Task"/> representing the running operation</returns>
|
||||
Task OnlineInstance(Models.Instance metadata, CancellationToken cancellationToken);
|
||||
Task OnlineInstance(Host.Models.Instance metadata, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Offline an <see cref="IInstance"/>
|
||||
/// </summary>
|
||||
/// <param name="metadata">The <see cref="Models.Instance"/> of the desired <see cref="IInstance"/></param>
|
||||
/// <param name="metadata">The <see cref="Host.Models.Instance"/> of the desired <see cref="IInstance"/></param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
|
||||
/// <returns>A <see cref="Task"/> representing the running operation</returns>
|
||||
Task OfflineInstance(Models.Instance metadata, CancellationToken cancellationToken);
|
||||
Task OfflineInstance(Host.Models.Instance metadata, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Move an <see cref="IInstance"/>
|
||||
/// </summary>
|
||||
/// <param name="metadata">The <see cref="Models.Instance"/> of the desired <see cref="IInstance"/></param>
|
||||
/// <param name="metadata">The <see cref="Host.Models.Instance"/> of the desired <see cref="IInstance"/></param>
|
||||
/// <param name="newPath">The new path of the <see cref="IInstance"/>. <paramref name="metadata"/> will have this set on <see cref="Api.Models.Instance.Path"/> if the operation completes successfully</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
|
||||
/// <returns>A <see cref="Task"/> representing the running operation</returns>
|
||||
Task MoveInstance(Models.Instance metadata, string newPath, CancellationToken cancellationToken);
|
||||
Task MoveInstance(Host.Models.Instance metadata, string newPath, CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,8 @@ namespace Tgstation.Server.Host.Components
|
||||
Configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
|
||||
}
|
||||
|
||||
public Api.Models.Instance GetMetadata() => metadata.CloneMetadata();
|
||||
|
||||
public void Rename(string newName)
|
||||
{
|
||||
if (String.IsNullOrWhiteSpace(newName))
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace Tgstation.Server.Host.Components
|
||||
|
||||
public InstanceFactory(IIOManager ioManager) => this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager));
|
||||
/// <inheritdoc />
|
||||
public IInstance CreateInstance(Models.Instance metadata)
|
||||
public IInstance CreateInstance(Host.Models.Instance metadata)
|
||||
{
|
||||
//Create the ioManager for the instance
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace Tgstation.Server.Host.Components
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IInstance GetInstance(Models.Instance metadata)
|
||||
public IInstance GetInstance(Host.Models.Instance metadata)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
@@ -58,7 +58,7 @@ namespace Tgstation.Server.Host.Components
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task MoveInstance(Models.Instance instance, string newPath, CancellationToken cancellationToken)
|
||||
public async Task MoveInstance(Host.Models.Instance instance, string newPath, CancellationToken cancellationToken)
|
||||
{
|
||||
if (newPath == null)
|
||||
throw new ArgumentNullException(nameof(newPath));
|
||||
@@ -84,7 +84,7 @@ namespace Tgstation.Server.Host.Components
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task OfflineInstance(Models.Instance metadata, CancellationToken cancellationToken)
|
||||
public async Task OfflineInstance(Host.Models.Instance metadata, CancellationToken cancellationToken)
|
||||
{
|
||||
IInstance instance;
|
||||
lock (this)
|
||||
@@ -97,7 +97,7 @@ namespace Tgstation.Server.Host.Components
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task OnlineInstance(Models.Instance metadata, CancellationToken cancellationToken)
|
||||
public async Task OnlineInstance(Host.Models.Instance metadata, CancellationToken cancellationToken)
|
||||
{
|
||||
var instance = instanceFactory.CreateInstance(metadata);
|
||||
lock (this)
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
using System.Collections.Generic;
|
||||
using Tgstation.Server.Api.Models.Internal;
|
||||
|
||||
namespace Tgstation.Server.Host.Components.Models
|
||||
{
|
||||
sealed class InteropInfo
|
||||
{
|
||||
public string AccessToken { get; set; }
|
||||
|
||||
public long InstanceId { get; set; }
|
||||
|
||||
public string HostPath { get; set; }
|
||||
|
||||
public bool ApiValidateOnly { get; set; }
|
||||
|
||||
public string InstanceName { get; set; }
|
||||
|
||||
public ushort NextPort { get; set; }
|
||||
|
||||
public string ChatChannelsJson { get; set; }
|
||||
|
||||
public string ChatCommandsJson { get; set; }
|
||||
|
||||
public RevisionInformation Revision { get; set; }
|
||||
|
||||
public List<TestMerge> TestMerges { get; } = new List<TestMerge>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using Tgstation.Server.Api.Models.Internal;
|
||||
|
||||
namespace Tgstation.Server.Host.Components.Models
|
||||
{
|
||||
sealed class TestMerge : RevisionInformation
|
||||
{
|
||||
public int Number { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string Body { get; set; }
|
||||
public string Author { get; set; }
|
||||
public string Url { get; set; }
|
||||
public string PullRequestCommit { get; set; }
|
||||
public long TimeMerged { get; set; }
|
||||
public string Comment { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Tgstation.Server.Api.Models.Internal;
|
||||
using Tgstation.Server.Host.Components.Models;
|
||||
using Tgstation.Server.Host.Core;
|
||||
using Tgstation.Server.Host.Security;
|
||||
|
||||
namespace Tgstation.Server.Host.Components
|
||||
@@ -14,6 +16,10 @@ namespace Tgstation.Server.Host.Components
|
||||
/// </summary>
|
||||
readonly IByond byond;
|
||||
/// <summary>
|
||||
/// The <see cref="IChat"/> for the <see cref="Watchdog"/>
|
||||
/// </summary>
|
||||
readonly IChat chat;
|
||||
/// <summary>
|
||||
/// The <see cref="IDreamDaemonExecutor"/> for the <see cref="Watchdog"/>
|
||||
/// </summary>
|
||||
readonly IDreamDaemonExecutor dreamDaemonExecutor;
|
||||
@@ -33,6 +39,14 @@ namespace Tgstation.Server.Host.Components
|
||||
/// The <see cref="IEventConsumer"/> for the <see cref="Watchdog"/>
|
||||
/// </summary>
|
||||
readonly IEventConsumer eventConsumer;
|
||||
/// <summary>
|
||||
/// The <see cref="IInstanceManager"/> for the <see cref="Watchdog"/>
|
||||
/// </summary>
|
||||
readonly IInstanceManager instanceManager;
|
||||
/// <summary>
|
||||
/// The <see cref="Api.Models.Instance.Id"/> of the <see cref="Watchdog"/>
|
||||
/// </summary>
|
||||
readonly long instanceId;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the currently running <see cref="Watchdog"/>
|
||||
@@ -47,19 +61,26 @@ namespace Tgstation.Server.Host.Components
|
||||
/// Construct a <see cref="IWatchdog"/>
|
||||
/// </summary>
|
||||
/// <param name="byond">The value of <see cref="byond"/></param>
|
||||
/// <param name="chat">The value of <see cref="chat"/></param>
|
||||
/// <param name="dreamDaemonExecutor">The value of <see cref="dreamDaemonExecutor"/></param>
|
||||
/// <param name="interop">The value of <see cref="interop"/></param>
|
||||
/// <param name="dmbFactory">The value of <see cref="dmbFactory"/></param>
|
||||
/// <param name="cryptographySuite">The value of <see cref="cryptographySuite"/></param>
|
||||
/// <param name="eventConsumer">The value of <see cref="eventConsumer"/></param>
|
||||
public Watchdog(IByond byond, IDreamDaemonExecutor dreamDaemonExecutor, IInterop interop, IDmbFactory dmbFactory, ICryptographySuite cryptographySuite, IEventConsumer eventConsumer)
|
||||
/// <param name="instanceManager">The value of <see cref="instanceManager"/></param>
|
||||
/// <param name="instanceId">The value of <see cref="instanceId"/></param>
|
||||
public Watchdog(IByond byond, IChat chat, IDreamDaemonExecutor dreamDaemonExecutor, IInterop interop, IDmbFactory dmbFactory, ICryptographySuite cryptographySuite, IEventConsumer eventConsumer, IInstanceManager instanceManager, long instanceId)
|
||||
{
|
||||
this.byond = byond ?? throw new ArgumentNullException(nameof(byond));
|
||||
this.chat = chat ?? throw new ArgumentNullException(nameof(chat));
|
||||
this.dreamDaemonExecutor = dreamDaemonExecutor ?? throw new ArgumentNullException(nameof(dreamDaemonExecutor));
|
||||
this.interop = interop ?? throw new ArgumentNullException(nameof(interop));
|
||||
this.dmbFactory = dmbFactory ?? throw new ArgumentNullException(nameof(dmbFactory));
|
||||
this.cryptographySuite = cryptographySuite ?? throw new ArgumentNullException(nameof(cryptographySuite));
|
||||
this.eventConsumer = eventConsumer ?? throw new ArgumentNullException(nameof(eventConsumer));
|
||||
this.instanceManager = instanceManager ?? throw new ArgumentNullException(nameof(instanceManager));
|
||||
|
||||
this.instanceId = instanceId;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -70,19 +91,47 @@ namespace Tgstation.Server.Host.Components
|
||||
/// </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="accessToken">The access token for the server</param>
|
||||
/// <param name="interopInfo">The <see cref="InteropInfo"/> the server</param>
|
||||
/// <param name="dreamDaemonPath">The path to the DreamDaemon executable</param>
|
||||
/// <param name="isPrimary">If a primary server is being launched</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, string accessToken, string dreamDaemonPath, bool isPrimary, 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))
|
||||
return await dreamDaemonExecutor.RunDreamDaemon(launchParameters, onSuccessfulStartup, dreamDaemonPath, String.Concat(dmb.PrimaryDirectory, dmb.DmbName), accessToken, isPrimary, false, cancellationToken).ConfigureAwait(false);
|
||||
{
|
||||
var chatJsonGuid = Guid.NewGuid();
|
||||
var isPrimary = interopInfo.NextPort == launchParameters.SecondaryPort;
|
||||
|
||||
//set up chat stuff
|
||||
interopInfo.ChatChannelsJson = String.Concat(chatJsonGuid, ".channels.json");
|
||||
//only track chat commands from primary server
|
||||
if(isPrimary)
|
||||
interopInfo.ChatCommandsJson = String.Concat(chatJsonGuid, ".commands.json");
|
||||
|
||||
//set up revision
|
||||
interopInfo.Revision = dmb.RevisionInformation;
|
||||
foreach (var I in dmb.RevisionInformation.TestMerges)
|
||||
interopInfo.TestMerges.Add(new Models.TestMerge
|
||||
{
|
||||
Author = I.Author,
|
||||
Body = I.BodyAtMerge,
|
||||
Comment = I.Comment,
|
||||
Commit = I.RevisionInformation.Commit,
|
||||
OriginRevision = I.RevisionInformation.OriginRevision,
|
||||
Number = I.Number,
|
||||
PullRequestCommit = I.PullRequestRevision,
|
||||
TimeMerged = I.MergedAt.ToUnixTimeSeconds(),
|
||||
Title = I.TitleAtMerge,
|
||||
Url = I.Url.ToString()
|
||||
});
|
||||
|
||||
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, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Locks in a <see cref="IByond"/> version and runs a server through <see cref="RunServer(DreamDaemonLaunchParameters, TaskCompletionSource{object}, string, string, bool, CancellationToken)"/>
|
||||
/// 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>
|
||||
@@ -97,7 +146,18 @@ namespace Tgstation.Server.Host.Components
|
||||
try
|
||||
{
|
||||
var ddToken = cancellationTokenSource.Token;
|
||||
var ddTask = byond.UseExecutable(dreamDaemonPath => RunServer(launchParameters, onSuccessfulStartup, accessToken, dreamDaemonPath, isPrimary, ddToken), false, true);
|
||||
|
||||
var interopInfo = new InteropInfo
|
||||
{
|
||||
AccessToken = accessToken,
|
||||
ApiValidateOnly = false,
|
||||
HostPath = Application.HostingPath,
|
||||
InstanceId = instanceId,
|
||||
NextPort = isPrimary ? launchParameters.SecondaryPort : launchParameters.PrimaryPort,
|
||||
InstanceName = instanceManager.GetInstance(new Host.Models.Instance { Id = instanceId }).GetMetadata().Name,
|
||||
};
|
||||
|
||||
var ddTask = byond.UseExecutable(dreamDaemonPath => RunServer(launchParameters, onSuccessfulStartup, interopInfo, dreamDaemonPath, ddToken), false, true);
|
||||
interop.SetRun(isPrimary ? launchParameters.PrimaryPort : launchParameters.SecondaryPort, accessToken, isPrimary);
|
||||
return ddTask;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Hosting.Server.Features;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
@@ -10,6 +11,7 @@ using Microsoft.IdentityModel.Tokens;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Tgstation.Server.Host.Components;
|
||||
using Tgstation.Server.Host.Configuration;
|
||||
@@ -24,6 +26,11 @@ namespace Tgstation.Server.Host.Core
|
||||
/// </summary>
|
||||
sealed class Application
|
||||
{
|
||||
/// <summary>
|
||||
/// The url the server can be reached at locally
|
||||
/// </summary>
|
||||
public static string HostingPath { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The version of the <see cref="Application"/>
|
||||
/// </summary>
|
||||
@@ -151,6 +158,9 @@ namespace Tgstation.Server.Host.Core
|
||||
if (applicationBuilder == null)
|
||||
throw new ArgumentNullException(nameof(applicationBuilder));
|
||||
|
||||
var addresses = applicationBuilder.ServerFeatures.Get<IServerAddressesFeature>();
|
||||
HostingPath = addresses.Addresses.First();
|
||||
|
||||
if (hostingEnvironment.IsDevelopment())
|
||||
applicationBuilder.UseDeveloperExceptionPage();
|
||||
|
||||
|
||||
@@ -109,7 +109,7 @@ namespace Tgstation.Server.Host.Models
|
||||
LogModelBuilderHelper.Build(modelBuilder.Entity<Log>());
|
||||
modelBuilder.Entity<Log>().ToTable(nameof(Logs));
|
||||
|
||||
modelBuilder.Entity<RevisionInformation>().HasIndex(x => x.Revision).IsUnique();
|
||||
modelBuilder.Entity<RevisionInformation>().HasIndex(x => x.Commit).IsUnique();
|
||||
var user = modelBuilder.Entity<User>();
|
||||
user.HasIndex(x => new { x.Name, x.SystemIdentifier }).IsUnique();
|
||||
user.HasOne(x => x.CreatedBy).WithMany(x => x.CreatedUsers).OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
@@ -10,5 +10,10 @@ namespace Tgstation.Server.Host.Models
|
||||
/// </summary>
|
||||
[Required]
|
||||
public User MergedBy { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="Models.RevisionInformation"/> for the <see cref="TestMerge"/>
|
||||
/// </summary>
|
||||
public RevisionInformation RevisionInformation { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user