diff --git a/src/DMAPI/tgs/v4/api.dm b/src/DMAPI/tgs/v4/api.dm index e5e40bb9eb..e8ba604067 100644 --- a/src/DMAPI/tgs/v4/api.dm +++ b/src/DMAPI/tgs/v4/api.dm @@ -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) diff --git a/src/DMAPI/tgs/v4/commands.dm b/src/DMAPI/tgs/v4/commands.dm index bf32f360e3..0d4e72f0fc 100644 --- a/src/DMAPI/tgs/v4/commands.dm +++ b/src/DMAPI/tgs/v4/commands.dm @@ -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) diff --git a/src/Tgstation.Server.Api/Models/Instance.cs b/src/Tgstation.Server.Api/Models/Instance.cs index bde9f13522..22bd31e1be 100644 --- a/src/Tgstation.Server.Api/Models/Instance.cs +++ b/src/Tgstation.Server.Api/Models/Instance.cs @@ -40,5 +40,15 @@ namespace Tgstation.Server.Api.Models /// [Permissions(WriteRight = InstanceManagerRights.SetConfiguration)] public bool ConfigurationAllowed { get; set; } + + /// + public Instance CloneMetadata() => new Instance + { + Id = Id, + Name = Name, + Path = Path, + Online = Online, + ConfigurationAllowed = ConfigurationAllowed + }; } } diff --git a/src/Tgstation.Server.Api/Models/Internal/RevisionInformation.cs b/src/Tgstation.Server.Api/Models/Internal/RevisionInformation.cs index 44eb907a89..a61788167f 100644 --- a/src/Tgstation.Server.Api/Models/Internal/RevisionInformation.cs +++ b/src/Tgstation.Server.Api/Models/Internal/RevisionInformation.cs @@ -12,7 +12,7 @@ namespace Tgstation.Server.Api.Models.Internal /// [Permissions(DenyWrite = true)] [Required, StringLength(40)] - public string Revision { get; set; } + public string Commit { get; set; } /// /// The sha of the most recent remote commit diff --git a/src/Tgstation.Server.Api/Models/Internal/TestMerge.cs b/src/Tgstation.Server.Api/Models/Internal/TestMerge.cs index 9e1d04f64d..fd6052390a 100644 --- a/src/Tgstation.Server.Api/Models/Internal/TestMerge.cs +++ b/src/Tgstation.Server.Api/Models/Internal/TestMerge.cs @@ -31,6 +31,12 @@ namespace Tgstation.Server.Api.Models.Internal [Required] public string BodyAtMerge { get; set; } + /// + /// The URL of the pull request + /// + [Required] + public Uri Url { get; set; } + /// /// The author of the pull request /// diff --git a/src/Tgstation.Server.Host/Components/DreamDaemonExecutor.cs b/src/Tgstation.Server.Host/Components/DreamDaemonExecutor.cs index f8b74ce401..0f3a47b026 100644 --- a/src/Tgstation.Server.Host/Components/DreamDaemonExecutor.cs +++ b/src/Tgstation.Server.Host/Components/DreamDaemonExecutor.cs @@ -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 } /// - public async Task RunDreamDaemon(DreamDaemonLaunchParameters launchParameters, TaskCompletionSource onSuccessfulStartup, string dreamDaemonPath, string dmbPath, string accessToken, bool usePrimaryPort, bool alwaysKill, CancellationToken cancellationToken) + public async Task RunDreamDaemon(DreamDaemonLaunchParameters launchParameters, TaskCompletionSource 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(); @@ -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(); diff --git a/src/Tgstation.Server.Host/Components/DreamDaemonParameters.cs b/src/Tgstation.Server.Host/Components/DreamDaemonParameters.cs index e5138d54da..4c7088c69e 100644 --- a/src/Tgstation.Server.Host/Components/DreamDaemonParameters.cs +++ b/src/Tgstation.Server.Host/Components/DreamDaemonParameters.cs @@ -3,12 +3,12 @@ static class DreamDaemonParameters { /// - /// Do not change to keep forwards/backwards api compatibility + /// Host version. Do not change to keep forwards/backwards api compatibility /// - 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"; + /// + /// Path to json + /// + public const string InfoJsonPath = "tgs_json"; } } diff --git a/src/Tgstation.Server.Host/Components/IChat.cs b/src/Tgstation.Server.Host/Components/IChat.cs index 9ebd0877c2..bd43137bca 100644 --- a/src/Tgstation.Server.Host/Components/IChat.cs +++ b/src/Tgstation.Server.Host/Components/IChat.cs @@ -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 to a given set of /// /// The message being sent - /// The s of the s to send to + /// The s of the s to send to /// The for the operation /// A representing the running operation Task SendMessage(string message, IEnumerable channelIds, CancellationToken cancellationToken); + + Task TrackJsons(string basePath, string channelsJsonName, string commandsJsonName, CancellationToken cancellationToken); } } \ No newline at end of file diff --git a/src/Tgstation.Server.Host/Components/IDmbProvider.cs b/src/Tgstation.Server.Host/Components/IDmbProvider.cs index b0d190ab34..4825fb2914 100644 --- a/src/Tgstation.Server.Host/Components/IDmbProvider.cs +++ b/src/Tgstation.Server.Host/Components/IDmbProvider.cs @@ -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 /// string SecondaryDirectory { get; } + + /// + /// The of the .dmb + /// + RevisionInformation RevisionInformation { get; } } } diff --git a/src/Tgstation.Server.Host/Components/IDreamDaemonExecutor.cs b/src/Tgstation.Server.Host/Components/IDreamDaemonExecutor.cs index c6e444cecd..2f7cbc150d 100644 --- a/src/Tgstation.Server.Host/Components/IDreamDaemonExecutor.cs +++ b/src/Tgstation.Server.Host/Components/IDreamDaemonExecutor.cs @@ -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 /// The /// The that is completed when dream daemon starts without crashing /// The path to the dreamdaemon executable - /// The path to the .dmb to run, the working directory will be derived from this - /// The access token to be used for communication - /// If the server should open on or of + /// The for the .dmb to run + /// The for the run /// If the resulting process should never be left alive /// The for the operation /// A representing the lifetime of the process and resulting in the exit code - Task RunDreamDaemon(DreamDaemonLaunchParameters launchParameters, TaskCompletionSource onSuccessfulStartup, string dreamDaemonPath, string dmbPath, string accessToken, bool usePrimaryPort, bool alwaysKill, CancellationToken cancellationToken); + Task RunDreamDaemon(DreamDaemonLaunchParameters launchParameters, TaskCompletionSource onSuccessfulStartup, string dreamDaemonPath, IDmbProvider dmbProvider, InteropInfo interopInfo, bool alwaysKill, CancellationToken cancellationToken); } } diff --git a/src/Tgstation.Server.Host/Components/IInstance.cs b/src/Tgstation.Server.Host/Components/IInstance.cs index d28a32d9a6..3735a5cc13 100644 --- a/src/Tgstation.Server.Host/Components/IInstance.cs +++ b/src/Tgstation.Server.Host/Components/IInstance.cs @@ -16,6 +16,8 @@ namespace Tgstation.Server.Host.Components IConfiguration Configuration { get; } + Api.Models.Instance GetMetadata(); + void Rename(string newName); } } \ No newline at end of file diff --git a/src/Tgstation.Server.Host/Components/IInstanceFactory.cs b/src/Tgstation.Server.Host/Components/IInstanceFactory.cs index a31d69f2f4..21d905f7a4 100644 --- a/src/Tgstation.Server.Host/Components/IInstanceFactory.cs +++ b/src/Tgstation.Server.Host/Components/IInstanceFactory.cs @@ -2,8 +2,16 @@ namespace Tgstation.Server.Host.Components { + /// + /// Factory for creating s + /// interface IInstanceFactory { - IInstance CreateInstance(Models.Instance metadata); + /// + /// Create an + /// + /// The + /// A new + IInstance CreateInstance(Host.Models.Instance metadata); } } \ No newline at end of file diff --git a/src/Tgstation.Server.Host/Components/IInstanceManager.cs b/src/Tgstation.Server.Host/Components/IInstanceManager.cs index 080ab59d06..34c5f6123c 100644 --- a/src/Tgstation.Server.Host/Components/IInstanceManager.cs +++ b/src/Tgstation.Server.Host/Components/IInstanceManager.cs @@ -11,33 +11,33 @@ namespace Tgstation.Server.Host.Components /// /// Get the associated with given /// - /// The of the desired + /// The of the desired /// The associated with the given - IInstance GetInstance(Models.Instance metadata); + IInstance GetInstance(Host.Models.Instance metadata); /// /// Online an /// - /// The of the desired + /// The of the desired /// The for the operation /// A representing the running operation - Task OnlineInstance(Models.Instance metadata, CancellationToken cancellationToken); + Task OnlineInstance(Host.Models.Instance metadata, CancellationToken cancellationToken); /// /// Offline an /// - /// The of the desired + /// The of the desired /// The for the operation /// A representing the running operation - Task OfflineInstance(Models.Instance metadata, CancellationToken cancellationToken); + Task OfflineInstance(Host.Models.Instance metadata, CancellationToken cancellationToken); /// /// Move an /// - /// The of the desired + /// The of the desired /// The new path of the . will have this set on if the operation completes successfully /// The for the operation /// A representing the running operation - Task MoveInstance(Models.Instance metadata, string newPath, CancellationToken cancellationToken); + Task MoveInstance(Host.Models.Instance metadata, string newPath, CancellationToken cancellationToken); } } diff --git a/src/Tgstation.Server.Host/Components/Instance.cs b/src/Tgstation.Server.Host/Components/Instance.cs index e31e5177c6..ce439ee988 100644 --- a/src/Tgstation.Server.Host/Components/Instance.cs +++ b/src/Tgstation.Server.Host/Components/Instance.cs @@ -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)) diff --git a/src/Tgstation.Server.Host/Components/InstanceFactory.cs b/src/Tgstation.Server.Host/Components/InstanceFactory.cs index d003ad7051..d241d749de 100644 --- a/src/Tgstation.Server.Host/Components/InstanceFactory.cs +++ b/src/Tgstation.Server.Host/Components/InstanceFactory.cs @@ -10,7 +10,7 @@ namespace Tgstation.Server.Host.Components public InstanceFactory(IIOManager ioManager) => this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); /// - public IInstance CreateInstance(Models.Instance metadata) + public IInstance CreateInstance(Host.Models.Instance metadata) { //Create the ioManager for the instance diff --git a/src/Tgstation.Server.Host/Components/InstanceManager.cs b/src/Tgstation.Server.Host/Components/InstanceManager.cs index 1032aff8fa..59f4ee867c 100644 --- a/src/Tgstation.Server.Host/Components/InstanceManager.cs +++ b/src/Tgstation.Server.Host/Components/InstanceManager.cs @@ -47,7 +47,7 @@ namespace Tgstation.Server.Host.Components } /// - public IInstance GetInstance(Models.Instance metadata) + public IInstance GetInstance(Host.Models.Instance metadata) { lock (this) { @@ -58,7 +58,7 @@ namespace Tgstation.Server.Host.Components } /// - 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 } /// - 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 } /// - 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) diff --git a/src/Tgstation.Server.Host/Components/Models/InteropInfo.cs b/src/Tgstation.Server.Host/Components/Models/InteropInfo.cs new file mode 100644 index 0000000000..1376421631 --- /dev/null +++ b/src/Tgstation.Server.Host/Components/Models/InteropInfo.cs @@ -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 TestMerges { get; } = new List(); + } +} diff --git a/src/Tgstation.Server.Host/Components/Models/TestMerge.cs b/src/Tgstation.Server.Host/Components/Models/TestMerge.cs new file mode 100644 index 0000000000..1996ad5bc3 --- /dev/null +++ b/src/Tgstation.Server.Host/Components/Models/TestMerge.cs @@ -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; } + } +} diff --git a/src/Tgstation.Server.Host/Components/Watchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog.cs index 71688ed6fe..f7eaf3d327 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog.cs @@ -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 /// readonly IByond byond; /// + /// The for the + /// + readonly IChat chat; + /// /// The for the /// readonly IDreamDaemonExecutor dreamDaemonExecutor; @@ -33,6 +39,14 @@ namespace Tgstation.Server.Host.Components /// The for the /// readonly IEventConsumer eventConsumer; + /// + /// The for the + /// + readonly IInstanceManager instanceManager; + /// + /// The of the + /// + readonly long instanceId; /// /// Represents the currently running @@ -47,19 +61,26 @@ namespace Tgstation.Server.Host.Components /// Construct a /// /// The value of + /// The value of /// The value of /// The value of /// The value of /// The value of /// The value of - public Watchdog(IByond byond, IDreamDaemonExecutor dreamDaemonExecutor, IInterop interop, IDmbFactory dmbFactory, ICryptographySuite cryptographySuite, IEventConsumer eventConsumer) + /// The value of + /// The value of + 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; } /// @@ -70,19 +91,47 @@ namespace Tgstation.Server.Host.Components /// /// The for the run /// The to be completed once the server starts if any - /// The access token for the server + /// The the server /// The path to the DreamDaemon executable - /// If a primary server is being launched /// The for the operation /// A resulting in the exit code of DreamDaemon - async Task RunServer(DreamDaemonLaunchParameters launchParameters, TaskCompletionSource onSuccessfulStartup, string accessToken, string dreamDaemonPath, bool isPrimary, CancellationToken cancellationToken) + async Task RunServer(DreamDaemonLaunchParameters launchParameters, TaskCompletionSource 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); + } } /// - /// Locks in a version and runs a server through + /// Locks in a version and runs a server through /// /// The for the run /// The to be completed once the server starts if any @@ -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; } diff --git a/src/Tgstation.Server.Host/Core/Application.cs b/src/Tgstation.Server.Host/Core/Application.cs index cd65f38a98..095e08b516 100644 --- a/src/Tgstation.Server.Host/Core/Application.cs +++ b/src/Tgstation.Server.Host/Core/Application.cs @@ -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 /// sealed class Application { + /// + /// The url the server can be reached at locally + /// + public static string HostingPath { get; private set; } + /// /// The version of the /// @@ -151,6 +158,9 @@ namespace Tgstation.Server.Host.Core if (applicationBuilder == null) throw new ArgumentNullException(nameof(applicationBuilder)); + var addresses = applicationBuilder.ServerFeatures.Get(); + HostingPath = addresses.Addresses.First(); + if (hostingEnvironment.IsDevelopment()) applicationBuilder.UseDeveloperExceptionPage(); diff --git a/src/Tgstation.Server.Host/Models/DatabaseContext.cs b/src/Tgstation.Server.Host/Models/DatabaseContext.cs index 4dc62319ba..5f0ffef80f 100644 --- a/src/Tgstation.Server.Host/Models/DatabaseContext.cs +++ b/src/Tgstation.Server.Host/Models/DatabaseContext.cs @@ -109,7 +109,7 @@ namespace Tgstation.Server.Host.Models LogModelBuilderHelper.Build(modelBuilder.Entity()); modelBuilder.Entity().ToTable(nameof(Logs)); - modelBuilder.Entity().HasIndex(x => x.Revision).IsUnique(); + modelBuilder.Entity().HasIndex(x => x.Commit).IsUnique(); var user = modelBuilder.Entity(); user.HasIndex(x => new { x.Name, x.SystemIdentifier }).IsUnique(); user.HasOne(x => x.CreatedBy).WithMany(x => x.CreatedUsers).OnDelete(DeleteBehavior.Restrict); diff --git a/src/Tgstation.Server.Host/Models/TestMerge.cs b/src/Tgstation.Server.Host/Models/TestMerge.cs index e72fc66e3c..05e201c04b 100644 --- a/src/Tgstation.Server.Host/Models/TestMerge.cs +++ b/src/Tgstation.Server.Host/Models/TestMerge.cs @@ -10,5 +10,10 @@ namespace Tgstation.Server.Host.Models /// [Required] public User MergedBy { get; set; } + + /// + /// The for the + /// + public RevisionInformation RevisionInformation { get; set; } } }