diff --git a/src/DMAPI/tgs/v4/api.dm b/src/DMAPI/tgs/v4/api.dm
index 40da59cb0f..cde747ba1f 100644
--- a/src/DMAPI/tgs/v4/api.dm
+++ b/src/DMAPI/tgs/v4/api.dm
@@ -72,7 +72,7 @@
TGS_INFO_LOG("Validating API and exiting...")
Export(TGS4_COMM_VALIDATE)
del(world)
-
+
chat_channels_json_path = cached_json["chatChannelsJson"]
chat_commands_json_path = cached_json["chatCommandsJson"]
src.event_handler = event_handler
@@ -80,31 +80,34 @@
ListCustomCommands()
- . = TRUE
-
var/list/revisionData = cached_json["revision"]
- if(!revisionData)
- return
-
- cached_revision = new
- cached_revision.commit = revisionData["commitSha"]
- cached_revision.origin_commit = revisionData["originCommitSha"]
+ if(revisionData)
+ cached_revision = new
+ cached_revision.commit = revisionData["commitSha"]
+ cached_revision.origin_commit = revisionData["originCommitSha"]
cached_test_merges = list()
- var/json = cached_json["testMerges"]
- for(var/I in json)
+ var/list/json = cached_json["testMerges"]
+ for(var/entry in json)
var/datum/tgs_revision_information/test_merge/tm = new
- tm.number = text2num(I)
- var/list/entry = json[I]
- tm.pull_request_commit = entry["pullRequestRevision"]
- tm.author = entry["author"]
- tm.title = entry["title"]
- var/list/revInfo = entry["revision"]
- tm.commit = revInfo["commitSha"]
- tm.origin_commit = entry["originCommitSha"]
tm.time_merged = text2num(entry["timeMerged"])
- tm.comment = entry["comment"]
+
+ var/list/revInfo = entry["revision"]
+ if(revInfo)
+ tm.commit = revInfo["commitSha"]
+ tm.origin_commit = revInfo["originCommitSha"]
+
+ tm.title = entry["titleAtMerge"]
+ tm.body = entry["bodyAtMerge"]
tm.url = entry["url"]
+ tm.author = entry["author"]
+ tm.number = entry["number"]
+ tm.pull_request_commit = entry["pullRequestRevision"]
+ tm.comment = entry["comment"]
+
+ cached_test_merges += tm
+
+ return TRUE
/datum/tgs_api/v4/OnInitializationComplete()
Export(TGS4_COMM_SERVER_PRIMED)
@@ -138,7 +141,15 @@
return result
if(TGS4_TOPIC_EVENT)
intercepted_message_queue = list()
- event_handler.HandleEvent(text2num(params[TGS4_PARAMETER_DATA]))
+ var/list/event_notification = json_decode(params[TGS4_PARAMETER_DATA])
+ var/list/event_parameters = event_notification["Parameters"]
+
+ var/list/event_call = list(event_notification["Type"])
+ if(event_parameters)
+ event_call += event_parameters
+
+ event_handler.HandleEvent(arglist(event_call))
+
. = json_encode(intercepted_message_queue)
intercepted_message_queue = null
return
diff --git a/src/Tgstation.Server.Api/Models/DreamMaker.cs b/src/Tgstation.Server.Api/Models/DreamMaker.cs
index f50fb7ac64..121d4b2d52 100644
--- a/src/Tgstation.Server.Api/Models/DreamMaker.cs
+++ b/src/Tgstation.Server.Api/Models/DreamMaker.cs
@@ -7,12 +7,6 @@ namespace Tgstation.Server.Api.Models
///
public sealed class DreamMaker : DreamMakerSettings
{
- ///
- /// The last ran
- ///
- [Permissions(DenyWrite = true)]
- public CompileJob LastJob { get; set; }
-
///
/// The of the compiler
///
diff --git a/src/Tgstation.Server.Host/Components/Byond/WindowsByondInstaller.cs b/src/Tgstation.Server.Host/Components/Byond/WindowsByondInstaller.cs
index 6530a0cc4e..a17aa4eece 100644
--- a/src/Tgstation.Server.Host/Components/Byond/WindowsByondInstaller.cs
+++ b/src/Tgstation.Server.Host/Components/Byond/WindowsByondInstaller.cs
@@ -134,7 +134,7 @@ namespace Tgstation.Server.Host.Components.Byond
cancellationToken.ThrowIfCancellationRequested();
if (exitCode != 0)
- throw new Exception(String.Format(CultureInfo.InvariantCulture, "Failed to install included DirectX! Exit code: {0}", exitCode));
+ throw new JobException(String.Format(CultureInfo.InvariantCulture, "Failed to install included DirectX! Exit code: {0}", exitCode));
installedDirectX = true;
}
}
diff --git a/src/Tgstation.Server.Host/Components/Chat/Commands/ByondCommand.cs b/src/Tgstation.Server.Host/Components/Chat/Commands/ByondCommand.cs
index e9cb16011b..e707e1f46c 100644
--- a/src/Tgstation.Server.Host/Components/Chat/Commands/ByondCommand.cs
+++ b/src/Tgstation.Server.Host/Components/Chat/Commands/ByondCommand.cs
@@ -15,7 +15,7 @@ namespace Tgstation.Server.Host.Components.Chat.Commands
public string Name => "byond";
///
- public string HelpText => "Displays the installed Byond version";
+ public string HelpText => "Displays the active Byond version";
///
public bool AdminOnly => false;
diff --git a/src/Tgstation.Server.Host/Components/Chat/Commands/CommandFactory.cs b/src/Tgstation.Server.Host/Components/Chat/Commands/CommandFactory.cs
index 5f8acb3c5d..4841366c5a 100644
--- a/src/Tgstation.Server.Host/Components/Chat/Commands/CommandFactory.cs
+++ b/src/Tgstation.Server.Host/Components/Chat/Commands/CommandFactory.cs
@@ -77,6 +77,7 @@ namespace Tgstation.Server.Host.Components.Chat.Commands
{
new VersionCommand(application),
new ByondCommand(byondManager),
+ new RevisionCommand(watchdog, repositoryManager, instance),
new PullRequestsCommand(watchdog, repositoryManager, databaseContextFactory, instance),
new KekCommand()
};
diff --git a/src/Tgstation.Server.Host/Components/Chat/Commands/PullRequestsCommand.cs b/src/Tgstation.Server.Host/Components/Chat/Commands/PullRequestsCommand.cs
index f3e3233c9c..90db91a969 100644
--- a/src/Tgstation.Server.Host/Components/Chat/Commands/PullRequestsCommand.cs
+++ b/src/Tgstation.Server.Host/Components/Chat/Commands/PullRequestsCommand.cs
@@ -92,7 +92,7 @@ namespace Tgstation.Server.Host.Components.Chat.Commands
if (!results.Any())
return "None!";
- return String.Join(", ", results.Select(x => String.Format(CultureInfo.InvariantCulture, "#{0} as {1}", x.Number, x.PullRequestRevision.Substring(0, 7))));
+ return String.Join(", ", results.Select(x => String.Format(CultureInfo.InvariantCulture, "#{0} at {1}", x.Number, x.PullRequestRevision.Substring(0, 7))));
}
}
}
diff --git a/src/Tgstation.Server.Host/Components/Chat/Commands/RevisionCommand.cs b/src/Tgstation.Server.Host/Components/Chat/Commands/RevisionCommand.cs
new file mode 100644
index 0000000000..4212c0459d
--- /dev/null
+++ b/src/Tgstation.Server.Host/Components/Chat/Commands/RevisionCommand.cs
@@ -0,0 +1,75 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Tgstation.Server.Host.Components.Repository;
+using Tgstation.Server.Host.Components.Watchdog;
+
+namespace Tgstation.Server.Host.Components.Chat.Commands
+{
+ ///
+ /// For displaying
+ ///
+ sealed class RevisionCommand : ICommand
+ {
+ ///
+ public string Name => "revision";
+
+ ///
+ public string HelpText => "Display live commit sha. Add --repo to view repository revision";
+
+ ///
+ public bool AdminOnly => false;
+
+ ///
+ /// The for the
+ ///
+ readonly IWatchdog watchdog;
+
+ ///
+ /// The for the
+ ///
+ readonly IRepositoryManager repositoryManager;
+
+ ///
+ /// The for the
+ ///
+ readonly Models.Instance instance;
+
+ ///
+ /// Construct a
+ ///
+ /// The value of
+ /// The value of
+ /// The value of
+ public RevisionCommand(IWatchdog watchdog, IRepositoryManager repositoryManager, Models.Instance instance)
+ {
+ this.watchdog = watchdog ?? throw new ArgumentNullException(nameof(watchdog));
+ this.repositoryManager = repositoryManager ?? throw new ArgumentNullException(nameof(repositoryManager));
+ this.instance = instance ?? throw new ArgumentNullException(nameof(instance));
+ }
+
+ ///
+ public async Task Invoke(string arguments, User user, CancellationToken cancellationToken)
+ {
+ string result;
+ if (arguments.Split(' ').Any(x => x.ToUpperInvariant() == "--REPO"))
+ using (var repo = await repositoryManager.LoadRepository(cancellationToken).ConfigureAwait(false))
+ {
+ if (repo == null)
+ return "Repository unavailable!";
+ result = repo.Head;
+ }
+ else
+ {
+ if (!watchdog.Running)
+ return "Server offline!";
+ result = watchdog.ActiveCompileJob?.RevisionInformation.CommitSha;
+ }
+
+ return String.Format(CultureInfo.InvariantCulture, "^{0}", result);
+ }
+ }
+}
diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs
index 34fb84c64c..1e4f39d80d 100644
--- a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs
+++ b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs
@@ -280,9 +280,6 @@ namespace Tgstation.Server.Host.Components.Chat.Providers
}
client.Listen(false);
- if (client.Nickname != nickname)
- //run this now cause it has to go up and down the pipe for us to get a proper check
- client.GetIrcUser(nickname);
listenTask = Task.Factory.StartNew(() =>
{
diff --git a/src/Tgstation.Server.Host/Components/Compiler/DreamMaker.cs b/src/Tgstation.Server.Host/Components/Compiler/DreamMaker.cs
index 38e87fa118..c88bc67e91 100644
--- a/src/Tgstation.Server.Host/Components/Compiler/DreamMaker.cs
+++ b/src/Tgstation.Server.Host/Components/Compiler/DreamMaker.cs
@@ -135,14 +135,17 @@ namespace Tgstation.Server.Host.Components.Compiler
var timeoutAt = DateTimeOffset.Now.AddSeconds(timeout);
using (var controller = await sessionControllerFactory.LaunchNew(launchParameters, provider, byondLock, true, true, true, cancellationToken).ConfigureAwait(false))
{
+ var launchResult = await controller.LaunchResult.ConfigureAwait(false);
+
var now = DateTimeOffset.Now;
- if (now < timeoutAt)
+ if (now < timeoutAt && launchResult.StartupTime.HasValue)
{
var timeoutTask = Task.Delay(timeoutAt - now, cancellationToken);
await Task.WhenAny(controller.Lifetime, timeoutTask).ConfigureAwait(false);
cancellationToken.ThrowIfCancellationRequested();
}
+
if (!controller.Lifetime.IsCompleted)
{
logger.LogDebug("API validation timed out!");
@@ -173,7 +176,7 @@ namespace Tgstation.Server.Host.Components.Compiler
logger.LogDebug("DreamMaker exit code: {0}", exitCode);
job.Output = dm.GetCombinedOutput();
- logger.LogTrace("DreamMaker output: {0}", job.Output);
+ logger.LogTrace("DreamMaker output: {0}{1}", Environment.NewLine, job.Output);
return exitCode;
}
}
@@ -260,11 +263,7 @@ namespace Tgstation.Server.Host.Components.Compiler
lock (this)
{
if (Status != CompilerStatus.Idle)
- {
- job.Output = "There is already a compile in progress!";
- logger.LogInformation(job.Output);
- return job;
- }
+ throw new JobException("There is already a compile in progress!");
Status = CompilerStatus.Copying;
}
@@ -337,11 +336,7 @@ namespace Tgstation.Server.Host.Components.Compiler
logger.LogTrace("Searching for available .dmes...");
var path = (await ioManager.GetFilesWithExtension(dirA, DmeExtension, cancellationToken).ConfigureAwait(false)).FirstOrDefault();
if (path == default)
- {
- job.Output = "Unable to find any .dme!";
- logger.LogWarning(job.Output);
- return job;
- }
+ throw new JobException("Unable to find any .dme!");
var dmeWithExtension = ioManager.GetFileName(path);
job.DmeName = dmeWithExtension.Substring(0, dmeWithExtension.Length - DmeExtension.Length - 1);
}
@@ -369,7 +364,7 @@ namespace Tgstation.Server.Host.Components.Compiler
{
//server never validated or compile failed
await eventConsumer.HandleEvent(EventType.CompileFailure, new List { resolvedGameDirectory, exitCode == 0 ? "1" : "0" }, cancellationToken).ConfigureAwait(false);
- throw new Exception(exitCode == 0 ? "Validation of the TGS api failed!" : String.Format(CultureInfo.InvariantCulture, "DM exited with a non-zero code: {0}{1}", exitCode, job.Output));
+ throw new JobException(exitCode == 0 ? "Validation of the TGS api failed!" : String.Format(CultureInfo.InvariantCulture, "DM exited with a non-zero code: {0}{1}", exitCode, job.Output));
}
logger.LogTrace("Running post compile event...");
diff --git a/src/Tgstation.Server.Host/Components/Interop/EventNotification.cs b/src/Tgstation.Server.Host/Components/Interop/EventNotification.cs
new file mode 100644
index 0000000000..9c9811808d
--- /dev/null
+++ b/src/Tgstation.Server.Host/Components/Interop/EventNotification.cs
@@ -0,0 +1,20 @@
+using System.Collections.Generic;
+
+namespace Tgstation.Server.Host.Components.Interop
+{
+ ///
+ /// For notifying DD of s
+ ///
+ sealed class EventNotification
+ {
+ ///
+ /// The
+ ///
+ public EventType Type { get; set; }
+
+ ///
+ /// The event parameters
+ ///
+ public IEnumerable Parameters { get; set; }
+ }
+}
diff --git a/src/Tgstation.Server.Host/Components/Interop/TestMerge.cs b/src/Tgstation.Server.Host/Components/Interop/TestMerge.cs
index 9f2b4e247f..9e8b795b53 100644
--- a/src/Tgstation.Server.Host/Components/Interop/TestMerge.cs
+++ b/src/Tgstation.Server.Host/Components/Interop/TestMerge.cs
@@ -1,4 +1,6 @@
-using Tgstation.Server.Api.Models.Internal;
+using System;
+using System.Globalization;
+using Tgstation.Server.Api.Models.Internal;
namespace Tgstation.Server.Host.Components.Interop
{
@@ -10,7 +12,7 @@ namespace Tgstation.Server.Host.Components.Interop
///
/// The unix time of when the test merge was applied
///
- public long TimeMerged { get; set; }
+ public string TimeMerged { get; set; }
///
/// The of the
@@ -21,10 +23,11 @@ namespace Tgstation.Server.Host.Components.Interop
/// Construct a
///
/// The to build from
- public TestMerge(Models.TestMerge testMerge) : base(testMerge)
+ /// The value of
+ public TestMerge(Models.TestMerge testMerge, RevisionInformation revision) : base(testMerge)
{
- TimeMerged = testMerge.MergedAt.Ticks;
- Revision = testMerge.PrimaryRevisionInformation;
+ TimeMerged = testMerge.MergedAt.Ticks.ToString(CultureInfo.InvariantCulture);
+ Revision = revision ?? throw new ArgumentNullException(nameof(revision));
}
}
}
diff --git a/src/Tgstation.Server.Host/Components/Repository/Repository.cs b/src/Tgstation.Server.Host/Components/Repository/Repository.cs
index 2879581610..a792cfa9bc 100644
--- a/src/Tgstation.Server.Host/Components/Repository/Repository.cs
+++ b/src/Tgstation.Server.Host/Components/Repository/Repository.cs
@@ -35,7 +35,7 @@ namespace Tgstation.Server.Host.Components.Repository
public string GitHubRepoName { get; }
///
- public bool Tracking => repository.Head.IsTracking;
+ public bool Tracking => Reference != null && repository.Head.IsTracking;
///
public string Head => repository.Head.Tip.Sha;
diff --git a/src/Tgstation.Server.Host/Components/Watchdog/LaunchResult.cs b/src/Tgstation.Server.Host/Components/Watchdog/LaunchResult.cs
index 81b2be9fb9..feefa00201 100644
--- a/src/Tgstation.Server.Host/Components/Watchdog/LaunchResult.cs
+++ b/src/Tgstation.Server.Host/Components/Watchdog/LaunchResult.cs
@@ -9,9 +9,9 @@ namespace Tgstation.Server.Host.Components.Watchdog
public sealed class LaunchResult
{
///
- /// The time it took for to return
+ /// The time it took for to return. If the startup timed out
///
- public TimeSpan StartupTime { get; set; }
+ public TimeSpan? StartupTime { get; set; }
///
/// The if it exited
@@ -19,6 +19,6 @@ namespace Tgstation.Server.Host.Components.Watchdog
public int? ExitCode { get; set; }
///
- public override string ToString() => String.Format(CultureInfo.InvariantCulture, "Exit Code: {0}, Time {1}ms", ExitCode, StartupTime.TotalMilliseconds);
+ public override string ToString() => String.Format(CultureInfo.InvariantCulture, "Exit Code: {0}, Time {1}ms", ExitCode, StartupTime?.TotalMilliseconds);
}
}
\ No newline at end of file
diff --git a/src/Tgstation.Server.Host/Components/Watchdog/MonitorState.cs b/src/Tgstation.Server.Host/Components/Watchdog/MonitorState.cs
index 367c2c3e80..a4cd7172cd 100644
--- a/src/Tgstation.Server.Host/Components/Watchdog/MonitorState.cs
+++ b/src/Tgstation.Server.Host/Components/Watchdog/MonitorState.cs
@@ -1,16 +1,42 @@
-namespace Tgstation.Server.Host.Components.Watchdog
+using Newtonsoft.Json;
+
+namespace Tgstation.Server.Host.Components.Watchdog
{
+ ///
+ /// The (absolute) state of the
+ ///
sealed class MonitorState
{
+ ///
+ /// If the inactive server is being rebooted
+ ///
public bool RebootingInactiveServer { get; set; }
+ ///
+ /// If the inactive server has a .dmb and needs to be swapped in
+ ///
public bool InactiveServerHasStagedDmb { get; set; }
+ ///
+ /// If the inactive server is in an unrecoverable state
+ ///
public bool InactiveServerCritFail { get; set; }
+ ///
+ /// The next to take in
+ ///
public MonitorAction NextAction { get; set; }
+ ///
+ /// The active
+ ///
+ [JsonIgnore]
public ISessionController ActiveServer { get; set; }
+
+ ///
+ /// The inactive
+ ///
+ [JsonIgnore]
public ISessionController InactiveServer { get; set; }
}
}
diff --git a/src/Tgstation.Server.Host/Components/Watchdog/SessionController.cs b/src/Tgstation.Server.Host/Components/Watchdog/SessionController.cs
index 2b11617c11..6a6448678b 100644
--- a/src/Tgstation.Server.Host/Components/Watchdog/SessionController.cs
+++ b/src/Tgstation.Server.Host/Components/Watchdog/SessionController.cs
@@ -167,7 +167,8 @@ namespace Tgstation.Server.Host.Components.Watchdog
/// The value of
/// The value of
/// The value of
- public SessionController(ReattachInformation reattachInformation, IProcess process, IByondExecutableLock byondLock, IByondTopicSender byondTopicSender, IJsonTrackingContext chatJsonTrackingContext, ICommContext interopContext, IChat chat, ILogger logger)
+ /// The optional time to wait before failing the
+ public SessionController(ReattachInformation reattachInformation, IProcess process, IByondExecutableLock byondLock, IByondTopicSender byondTopicSender, IJsonTrackingContext chatJsonTrackingContext, ICommContext interopContext, IChat chat, ILogger logger, uint? startupTimeout)
{
this.chatJsonTrackingContext = chatJsonTrackingContext; //null valid
this.reattachInformation = reattachInformation ?? throw new ArgumentNullException(nameof(reattachInformation));
@@ -190,11 +191,17 @@ namespace Tgstation.Server.Host.Components.Watchdog
async Task GetLaunchResult()
{
var startTime = DateTimeOffset.Now;
- await process.Startup.ConfigureAwait(false);
+ Task toAwait = process.Startup;
+
+ if (startupTimeout.HasValue)
+ toAwait = Task.WhenAny(process.Startup, Task.Delay(startTime.AddSeconds(startupTimeout.Value) - startTime));
+
+ await toAwait.ConfigureAwait(false);
+
var result = new LaunchResult
{
ExitCode = process.Lifetime.IsCompleted ? (int?)await process.Lifetime.ConfigureAwait(false) : null,
- StartupTime = DateTimeOffset.Now - startTime
+ StartupTime = process.Startup.IsCompleted ? (TimeSpan?)(DateTimeOffset.Now - startTime) : null
};
return result;
};
@@ -420,5 +427,8 @@ namespace Tgstation.Server.Host.Components.Watchdog
CheckDisposed();
reattachInformation.RebootState = RebootState.Normal;
}
+
+ ///
+ public void SetHighPriority() => process.SetHighPriority();
}
}
diff --git a/src/Tgstation.Server.Host/Components/Watchdog/SessionControllerFactory.cs b/src/Tgstation.Server.Host/Components/Watchdog/SessionControllerFactory.cs
index 92d109e28b..d1de6c468a 100644
--- a/src/Tgstation.Server.Host/Components/Watchdog/SessionControllerFactory.cs
+++ b/src/Tgstation.Server.Host/Components/Watchdog/SessionControllerFactory.cs
@@ -131,6 +131,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
//i changed this back from guids, hopefully i don't regret that
string JsonFile(string name) => String.Format(CultureInfo.InvariantCulture, "{0}.{1}", name, JsonPostfix);
+ //setup interop files
var interopInfo = new JsonFile
{
AccessIdentifier = accessIdentifier,
@@ -139,10 +140,14 @@ namespace Tgstation.Server.Host.Components.Watchdog
ChatCommandsJson = JsonFile("chat_commands"),
ServerCommandsJson = JsonFile("server_commands"),
InstanceName = instance.Name,
- Revision = dmbProvider.CompileJob.RevisionInformation
+ Revision = new Api.Models.Internal.RevisionInformation
+ {
+ CommitSha = dmbProvider.CompileJob.RevisionInformation.CommitSha,
+ OriginCommitSha = dmbProvider.CompileJob.RevisionInformation.OriginCommitSha
+ }
};
- interopInfo.TestMerges.AddRange(dmbProvider.CompileJob.RevisionInformation.ActiveTestMerges.Select(x => x.TestMerge).Select(x => new Interop.TestMerge(x)));
+ interopInfo.TestMerges.AddRange(dmbProvider.CompileJob.RevisionInformation.ActiveTestMerges.Select(x => x.TestMerge).Select(x => new Interop.TestMerge(x, interopInfo.Revision)));
var interopJsonFile = JsonFile("interop");
@@ -163,15 +168,18 @@ namespace Tgstation.Server.Host.Components.Watchdog
var chatJsonTrackingContext = await chatJsonTrackingTask.ConfigureAwait(false);
try
{
+ //get the byond lock
var byondLock = currentByondLock ?? await byond.UseExecutables(Version.Parse(dmbProvider.CompileJob.ByondVersion), cancellationToken).ConfigureAwait(false);
try
{
- //more sanitization here cause it uses the same scheme
- var parameters = String.Format(CultureInfo.InvariantCulture, "{2}={0}&{3}={1}", byondTopicSender.SanitizeString(application.Version.ToString()), byondTopicSender.SanitizeString(interopJsonFile), byondTopicSender.SanitizeString(Constants.DMParamHostVersion), byondTopicSender.SanitizeString(Constants.DMParamInfoJson));
-
+ //create interop context
var context = new CommContext(ioManager, loggerFactory.CreateLogger(), basePath, interopInfo.ServerCommandsJson);
try
{
+ //set command line options
+ //more sanitization here cause it uses the same scheme
+ var parameters = String.Format(CultureInfo.InvariantCulture, "{2}={0}&{3}={1}", byondTopicSender.SanitizeString(application.Version.ToString()), byondTopicSender.SanitizeString(interopJsonFile), byondTopicSender.SanitizeString(Constants.DMParamHostVersion), byondTopicSender.SanitizeString(Constants.DMParamInfoJson));
+
var arguments = String.Format(CultureInfo.InvariantCulture, "{0} -port {1} {2}-close -{3} -verbose -public -params \"{4}\"",
dmbProvider.DmbName,
primaryPort ? launchParameters.PrimaryPort : launchParameters.SecondaryPort,
@@ -179,9 +187,11 @@ namespace Tgstation.Server.Host.Components.Watchdog
SecurityWord(launchParameters.SecurityLevel.Value),
parameters);
+ //launch dd
var process = processExecutor.LaunchProcess(byondLock.DreamDaemonPath, basePath, arguments);
try
{
+ //return the session controller for it
return new SessionController(new ReattachInformation
{
AccessIdentifier = accessIdentifier,
@@ -192,7 +202,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
ChatChannelsJson = interopInfo.ChatChannelsJson,
ChatCommandsJson = interopInfo.ChatCommandsJson,
ServerCommandsJson = interopInfo.ServerCommandsJson,
- }, process, byondLock, byondTopicSender, chatJsonTrackingContext, context, chat, loggerFactory.CreateLogger());
+ }, process, byondLock, byondTopicSender, chatJsonTrackingContext, context, chat, loggerFactory.CreateLogger(), launchParameters.StartupTimeout);
}
catch
{
@@ -239,7 +249,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
var process = processExecutor.GetProcess(reattachInformation.ProcessId);
try
{
- return new SessionController(reattachInformation, process, byondLock, byondTopicSender, chatJsonTrackingContext, context, chat, loggerFactory.CreateLogger());
+ return new SessionController(reattachInformation, process, byondLock, byondTopicSender, chatJsonTrackingContext, context, chat, loggerFactory.CreateLogger(), null);
}
catch
{
diff --git a/src/Tgstation.Server.Host/Components/Watchdog/Watchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/Watchdog.cs
index be572dc73d..b43720659f 100644
--- a/src/Tgstation.Server.Host/Components/Watchdog/Watchdog.cs
+++ b/src/Tgstation.Server.Host/Components/Watchdog/Watchdog.cs
@@ -20,9 +20,9 @@ namespace Tgstation.Server.Host.Components.Watchdog
sealed class Watchdog : IWatchdog, ICustomCommandHandler
{
///
- /// The time in milliseconds to wait from starting to start . Does not take responsiveness into account
+ /// The time in seconds to wait from starting to start . Does not take responsiveness into account
///
- const int AlphaBravoStartupSeperationInterval = 3000;
+ const int AlphaBravoStartupSeperationInterval = 3;
///
public bool Running { get; private set; }
@@ -187,6 +187,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
alphaServer = null;
bravoServer?.Dispose();
bravoServer = null;
+ Running = false;
}
///
@@ -232,7 +233,6 @@ namespace Tgstation.Server.Host.Components.Watchdog
var chatTask = announce ? chat.SendWatchdogMessage("Terminating...", cancellationToken) : Task.CompletedTask;
await StopMonitor().ConfigureAwait(false);
DisposeAndNullControllers();
- Running = false;
await chatTask.ConfigureAwait(false);
return;
}
@@ -320,7 +320,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
if (dmbBackup == null) //NANI!?
//just give up, if THAT compile job is failing then the ActiveServer is gonna crash soon too or already has
- throw new Exception("Creating backup DMB provider failed!");
+ throw new JobException("Creating backup DMB provider failed!");
monitorState.InactiveServer = await sessionControllerFactory.LaunchNew(ActiveLaunchParameters, dmbBackup, null, false, !monitorState.ActiveServer.IsPrimary, false, cancellationToken).ConfigureAwait(false);
usedMostRecentDmb = false;
@@ -411,7 +411,6 @@ namespace Tgstation.Server.Host.Components.Watchdog
case Components.Watchdog.RebootState.Shutdown:
await chat.SendWatchdogMessage("Active server rebooted! Exiting due to graceful termination request...", cancellationToken).ConfigureAwait(false);
DisposeAndNullControllers();
- Running = false;
monitorState.NextAction = MonitorAction.Exit;
return;
}
@@ -438,8 +437,6 @@ namespace Tgstation.Server.Host.Components.Watchdog
monitorState.NextAction = MonitorAction.Break;
break;
case MonitorActivationReason.InactiveServerRebooted:
- //should never happen but okay
- logger.LogWarning("Inactive server rebooted, this is a bug in DM code!");
monitorState.RebootingInactiveServer = true;
monitorState.InactiveServer.ResetRebootState(); //the DMAPI has already done this internally
monitorState.ActiveServer.ClosePortOnReboot = false;
@@ -492,7 +489,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
var inactiveServerLifetime = monitorState.InactiveServer.Lifetime;
var activeServerReboot = monitorState.ActiveServer.OnReboot;
var inactiveServerReboot = monitorState.InactiveServer.OnReboot;
- var inactiveServerStartup = monitorState.InactiveServer.LaunchResult;
+ var inactiveServerStartup = monitorState.RebootingInactiveServer ? monitorState.InactiveServer.LaunchResult : null;
var activeLaunchParametersChanged = activeParametersUpdated.Task;
var newDmbAvailable = dmbFactory.OnNewerDmb;
@@ -550,9 +547,11 @@ namespace Tgstation.Server.Host.Components.Watchdog
}
else
moreActivationsToProcess = false;
+
+ if(moreActivationsToProcess)
+ await HandlerMonitorWakeup(activationReason, monitorState, cancellationToken).ConfigureAwait(false);
}
- await HandlerMonitorWakeup(activationReason, monitorState, cancellationToken).ConfigureAwait(false);
//writeback alphaServer and bravoServer
alphaServer = AlphaIsActive ? monitorState.ActiveServer : monitorState.InactiveServer;
bravoServer = AlphaIsActive ? monitorState.ActiveServer : monitorState.InactiveServer;
@@ -576,7 +575,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
monitorState = new MonitorState(); //clean the slate
}
- await chatTask.ConfigureAwait(false);
+ await chatTask.ConfigureAwait(false);
if(!Running)
{
logger.LogWarning("Failed to automatically restart the watchdog! Alpha: {0}; Bravo: {1}", result.Alpha.ToString(), result.Bravo.ToString());
@@ -626,9 +625,9 @@ namespace Tgstation.Server.Host.Components.Watchdog
async Task LaunchNoLock(bool startMonitor, bool announce, bool doReattach, CancellationToken cancellationToken)
{
+ logger.LogTrace("Begin LaunchNoLock");
using (var alphaStartCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken))
{
- logger.LogTrace("Begin LaunchNoLock");
if (Running)
{
logger.LogTrace("Aborted due to already running!");
@@ -655,32 +654,43 @@ namespace Tgstation.Server.Host.Components.Watchdog
var doesntNeedNewDmb = doReattach && reattachInfo.Alpha != null && reattachInfo.Bravo != null;
var dmbToUse = doesntNeedNewDmb ? null : dmbFactory.LockNextDmb(2);
- Task alphaServerTask = null;
try
{
+ Task alphaServerTask;
if (!doesntNeedNewDmb)
alphaServerTask = sessionControllerFactory.LaunchNew(ActiveLaunchParameters, dmbToUse, null, true, true, false, alphaStartCts.Token);
else
alphaServerTask = sessionControllerFactory.Reattach(reattachInfo.Alpha, cancellationToken);
- //do a few seconds of delay so that any backends the servers use know that alpha came first
- await Task.Delay(AlphaBravoStartupSeperationInterval, cancellationToken).ConfigureAwait(false);
+
+ //wait until this boy officially starts so as not to confuse the servers as to who came first
+ var startTime = DateTimeOffset.Now;
+ alphaServer = await alphaServerTask.ConfigureAwait(false);
+ alphaServer.SetHighPriority();
+
+ //extra delay for total ordering
+ var now = DateTimeOffset.Now;
+ var delay = now - startTime;
+
+ if (delay.TotalSeconds < AlphaBravoStartupSeperationInterval)
+ await Task.Delay(startTime.AddSeconds(AlphaBravoStartupSeperationInterval) - now, cancellationToken).ConfigureAwait(false);
+
Task bravoServerTask;
if (!doesntNeedNewDmb)
bravoServerTask = sessionControllerFactory.LaunchNew(ActiveLaunchParameters, dmbToUse, null, false, false, false, cancellationToken);
else
bravoServerTask = sessionControllerFactory.Reattach(reattachInfo.Bravo, cancellationToken);
- await Task.WhenAll(alphaServerTask, bravoServerTask).ConfigureAwait(false);
-
- alphaServer = alphaServerTask.Result;
- bravoServer = bravoServerTask.Result;
+ bravoServer = await bravoServerTask.ConfigureAwait(false);
+ bravoServer.SetHighPriority();
async Task CheckLaunch(ISessionController controller, string serverName)
{
var launch = await controller.LaunchResult.ConfigureAwait(false);
if (launch.ExitCode.HasValue)
//you killed us ray...
- throw new Exception(String.Format(CultureInfo.InvariantCulture, "{1} server failed to start: {0}", launch.ToString(), serverName));
+ throw new JobException(String.Format(CultureInfo.InvariantCulture, "{1} server failed to start: {0}", launch.ToString(), serverName));
+ if (!launch.StartupTime.HasValue)
+ throw new JobException(String.Format(CultureInfo.InvariantCulture, "{1} server timed out on startup: {0}s", launch.ToString(), ActiveLaunchParameters.StartupTimeout.Value));
return launch;
}
@@ -793,12 +803,14 @@ namespace Tgstation.Server.Host.Components.Watchdog
return true;
var builder = new StringBuilder(Constants.DMTopicEvent);
- if (parameters != null)
- foreach (var I in parameters)
- {
- builder.Append("&");
- builder.Append(byondTopicSender.SanitizeString(I));
- }
+ builder.Append("&");
+ var notification = new EventNotification
+ {
+ Type = eventType,
+ Parameters = parameters
+ };
+ var json = JsonConvert.SerializeObject(notification);
+ builder.Append(byondTopicSender.SanitizeString(json));
var activeServer = AlphaIsActive ? alphaServer : bravoServer;
results = await activeServer.SendCommand(builder.ToString(), cancellationToken).ConfigureAwait(false);
diff --git a/src/Tgstation.Server.Host/Controllers/DreamMakerController.cs b/src/Tgstation.Server.Host/Controllers/DreamMakerController.cs
index fa46db3581..657e7fe3dc 100644
--- a/src/Tgstation.Server.Host/Controllers/DreamMakerController.cs
+++ b/src/Tgstation.Server.Host/Controllers/DreamMakerController.cs
@@ -49,12 +49,10 @@ namespace Tgstation.Server.Host.Controllers
public override async Task Read(CancellationToken cancellationToken)
{
var instance = instanceManager.GetInstance(Instance);
- var projectNameTask = DatabaseContext.DreamMakerSettings.Where(x => x.InstanceId == Instance.Id).Select(x => x.ProjectName).FirstOrDefaultAsync(cancellationToken);
- var job = await DatabaseContext.CompileJobs.OrderByDescending(x => x.Job.StartedAt).Include(x => x.Job).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
+ var projectName = await DatabaseContext.DreamMakerSettings.Where(x => x.InstanceId == Instance.Id).Select(x => x.ProjectName).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
return Json(new Api.Models.DreamMaker
{
- LastJob = job?.ToApi(),
- ProjectName = await projectNameTask.ConfigureAwait(false),
+ ProjectName = projectName,
Status = instance.DreamMaker.Status
});
}
diff --git a/src/Tgstation.Server.Host/Controllers/RepositoryController.cs b/src/Tgstation.Server.Host/Controllers/RepositoryController.cs
index beac22b255..77e7cfb95e 100644
--- a/src/Tgstation.Server.Host/Controllers/RepositoryController.cs
+++ b/src/Tgstation.Server.Host/Controllers/RepositoryController.cs
@@ -162,7 +162,7 @@ namespace Tgstation.Server.Host.Controllers
using (var repos = await repoManager.CloneRepository(new Uri(origin), cloneBranch, currentModel.AccessUser, currentModel.AccessToken, progressReporter, cancellationToken).ConfigureAwait(false))
{
if (repos == null)
- throw new Exception("Filesystem conflict while cloning repository!");
+ throw new JobException("Filesystem conflict while cloning repository!");
var db = serviceProvider.GetRequiredService();
if (await PopulateApi(api, repos, db, Instance, null, null, cancellationToken).ConfigureAwait(false))
await db.Save(cancellationToken).ConfigureAwait(false);
@@ -315,7 +315,7 @@ namespace Tgstation.Server.Host.Controllers
using (var repo = await instanceManager.GetInstance(Instance).RepositoryManager.LoadRepository(ct).ConfigureAwait(false))
{
if (repo == null)
- throw new InvalidOperationException("Repository could not be loaded!");
+ throw new JobException("Repository could not be loaded!");
var modelHasShaOrReference = model.CheckoutSha != null || model.Reference != null;
@@ -323,7 +323,7 @@ namespace Tgstation.Server.Host.Controllers
var startSha = repo.Head;
if (newTestMerges && !repo.IsGitHubRepository)
- throw new InvalidOperationException("Cannot test merge on a non GitHub based repository!");
+ throw new JobException("Cannot test merge on a non GitHub based repository!");
var committerName = currentModel.ShowTestMergeCommitters.Value ? AuthenticationContext.User.Name : currentModel.CommitterName;
@@ -357,15 +357,15 @@ namespace Tgstation.Server.Host.Controllers
//fetch/pull
if (model.UpdateFromOrigin == true)
{
- if (!repo.Tracking && model.Reference == null)
- throw new InvalidOperationException("Not on an updatable reference!");
+ if (!repo.Tracking)
+ throw new JobException("Not on an updatable reference!");
await repo.FetchOrigin(currentModel.AccessUser, currentModel.AccessToken, x => progressReporter(x / numFetches), ct).ConfigureAwait(false);
doneFetches = 1;
if (!modelHasShaOrReference)
{
var fastForward = await repo.MergeOrigin(committerName, currentModel.CommitterEmail, ct).ConfigureAwait(false);
if (!fastForward.HasValue)
- throw new InvalidOperationException("Merge conflict occurred during origin update!");
+ throw new JobException("Merge conflict occurred during origin update!");
await UpdateRevInfo().ConfigureAwait(false);
if (fastForward.Value)
{
@@ -388,7 +388,7 @@ namespace Tgstation.Server.Host.Controllers
if (model.UpdateFromOrigin == true && model.Reference != null)
{
if (!repo.Tracking)
- throw new InvalidOperationException("Checked out reference does not track a remote object!");
+ throw new JobException("Checked out reference does not track a remote object!");
await repo.ResetToOrigin(ct).ConfigureAwait(false);
await repo.Sychronize(currentModel.AccessUser, currentModel.AccessToken, true, ct).ConfigureAwait(false);
await LoadRevisionInformation(repo, databaseContext, attachedInstance, null, x => lastRevisionInfo = x, ct).ConfigureAwait(false);
@@ -412,6 +412,7 @@ namespace Tgstation.Server.Host.Controllers
var repoName = repo.GitHubRepoName;
Models.RevisionInformation revInfoWereLookingFor = null;
+ bool needToApplyRemainingPrs = true;
//optimization: if we've already merged these exact same commits in this fashion before, just find the rev info for it and check it out
if (lastRevisionInfo.OriginCommitSha == lastRevisionInfo.CommitSha)
{
@@ -445,20 +446,61 @@ namespace Tgstation.Server.Host.Controllers
if (!cantSearch)
{
var dbPull = await databaseContext.RevisionInformations
- .Where(x => x.Instance.Id == Instance.Id
- && x.OriginCommitSha == lastRevisionInfo.OriginCommitSha
- && x.ActiveTestMerges.Count == model.NewTestMerges.Count)
+ .Where(x => x.Instance.Id == Instance.Id
+ && x.OriginCommitSha == lastRevisionInfo.OriginCommitSha
+ && x.ActiveTestMerges.Count <= model.NewTestMerges.Count
+ && x.ActiveTestMerges.Count > 0)
.Include(x => x.ActiveTestMerges)
.ThenInclude(x => x.TestMerge)
.ToListAsync(cancellationToken).ConfigureAwait(false);
+
//split here cause this bit has to be done locally
revInfoWereLookingFor = dbPull
- .Where(x => x.ActiveTestMerges.Select(y => y.TestMerge)
- .All(y => model.NewTestMerges.Any(z =>
- y.Number == z.Number
- && y.PullRequestRevision.StartsWith(z.PullRequestRevision, StringComparison.Ordinal)
- && y.Comment?.Trim().ToUpperInvariant() == z.Comment?.Trim().ToUpperInvariant() || z.Comment == null)))
+ .Where(x => x.ActiveTestMerges.Count == model.NewTestMerges.Count
+ && x.ActiveTestMerges.Select(y => y.TestMerge)
+ .All(y => model.NewTestMerges.Any(z =>
+ y.Number == z.Number
+ && y.PullRequestRevision.StartsWith(z.PullRequestRevision, StringComparison.Ordinal)
+ && (y.Comment?.Trim().ToUpperInvariant() == z.Comment?.Trim().ToUpperInvariant() || z.Comment == null))))
.FirstOrDefault();
+
+ if (revInfoWereLookingFor == null && model.NewTestMerges.Count > 1)
+ {
+ //okay try to add at least SOME prs we've seen before
+ var search = model.NewTestMerges.ToList();
+
+ var appliedTestMergeIds = new List();
+
+ Models.RevisionInformation lastGoodRevInfo = null;
+ do
+ {
+ foreach (var I in search)
+ {
+ revInfoWereLookingFor = dbPull
+ .Where(x => model.NewTestMerges.Any(z =>
+ x.PrimaryTestMerge.Number == z.Number
+ && x.PrimaryTestMerge.PullRequestRevision.StartsWith(z.PullRequestRevision, StringComparison.Ordinal)
+ && (x.PrimaryTestMerge.Comment?.Trim().ToUpperInvariant() == z.Comment?.Trim().ToUpperInvariant() || z.Comment == null))
+ && x.ActiveTestMerges.Select(y => y.TestMerge).All(y => appliedTestMergeIds.Contains(y.Id)))
+ .FirstOrDefault();
+
+ if (revInfoWereLookingFor != null)
+ {
+ lastGoodRevInfo = revInfoWereLookingFor;
+ appliedTestMergeIds.Add(revInfoWereLookingFor.PrimaryTestMerge.Id);
+ search.Remove(I);
+ break;
+ }
+ }
+ } while (revInfoWereLookingFor != null && search.Count > 0);
+
+ revInfoWereLookingFor = lastGoodRevInfo;
+ needToApplyRemainingPrs = search.Count != 0;
+ if (needToApplyRemainingPrs)
+ model.NewTestMerges = search;
+ }
+ else if (revInfoWereLookingFor != null)
+ needToApplyRemainingPrs = false;
}
}
@@ -468,7 +510,8 @@ namespace Tgstation.Server.Host.Controllers
await repo.ResetToSha(revInfoWereLookingFor.CommitSha, cancellationToken).ConfigureAwait(false);
lastRevisionInfo = revInfoWereLookingFor;
}
- else
+
+ if(needToApplyRemainingPrs)
{
var contextUser = new Models.User
{
diff --git a/src/Tgstation.Server.Host/Core/IProcessBase.cs b/src/Tgstation.Server.Host/Core/IProcessBase.cs
index b96b93b2ae..cc287208c4 100644
--- a/src/Tgstation.Server.Host/Core/IProcessBase.cs
+++ b/src/Tgstation.Server.Host/Core/IProcessBase.cs
@@ -12,5 +12,10 @@ namespace Tgstation.Server.Host.Core
/// The resulting in the exit code of the process
///
Task Lifetime { get; }
+
+ ///
+ /// Set's the owned to
+ ///
+ void SetHighPriority();
}
}
diff --git a/src/Tgstation.Server.Host/Core/JobException.cs b/src/Tgstation.Server.Host/Core/JobException.cs
new file mode 100644
index 0000000000..88877c9548
--- /dev/null
+++ b/src/Tgstation.Server.Host/Core/JobException.cs
@@ -0,0 +1,34 @@
+using System;
+
+namespace Tgstation.Server.Host
+{
+ ///
+ /// Operation exceptions thrown from the context of a
+ ///
+ public sealed class JobException : Exception
+ {
+ ///
+ /// Construct a
+ ///
+ public JobException()
+ {
+ }
+
+ ///
+ /// Construct a with a
+ ///
+ /// The message for the
+ public JobException(string message) : base(message)
+ {
+ }
+
+ ///
+ /// Construct a with a and
+ ///
+ /// The message for the
+ /// The inner for the nase
+ public JobException(string message, Exception innerException) : base(message, innerException)
+ {
+ }
+ }
+}
diff --git a/src/Tgstation.Server.Host/Core/JobManager.cs b/src/Tgstation.Server.Host/Core/JobManager.cs
index e4e13aa4d9..4a9b60419f 100644
--- a/src/Tgstation.Server.Host/Core/JobManager.cs
+++ b/src/Tgstation.Server.Host/Core/JobManager.cs
@@ -95,7 +95,7 @@ namespace Tgstation.Server.Host.Core
catch (Exception e)
{
logger.LogDebug("Job {0} exited with error! Exception: {1}", job.Id, e);
- job.ExceptionDetails = e.ToString();
+ job.ExceptionDetails = e is JobException ? e.Message : e.ToString();
}
job.StoppedAt = DateTimeOffset.Now;
await databaseContext.Save(default).ConfigureAwait(false);
diff --git a/src/Tgstation.Server.Host/Core/Process.cs b/src/Tgstation.Server.Host/Core/Process.cs
index 45750daeaa..15296ebb2f 100644
--- a/src/Tgstation.Server.Host/Core/Process.cs
+++ b/src/Tgstation.Server.Host/Core/Process.cs
@@ -50,7 +50,7 @@ namespace Tgstation.Server.Host.Core
{
if (combinedStringBuilder == null)
throw new InvalidOperationException("Output/Error reading was not enabled!");
- return combinedStringBuilder.ToString();
+ return combinedStringBuilder.ToString().TrimStart(Environment.NewLine.ToCharArray());
}
///
@@ -58,7 +58,7 @@ namespace Tgstation.Server.Host.Core
{
if (errorStringBuilder == null)
throw new InvalidOperationException("Error reading was not enabled!");
- return errorStringBuilder.ToString();
+ return errorStringBuilder.ToString().TrimStart(Environment.NewLine.ToCharArray());
}
///
@@ -66,7 +66,7 @@ namespace Tgstation.Server.Host.Core
{
if (outputStringBuilder == null)
throw new InvalidOperationException("Output reading was not enabled!");
- return errorStringBuilder.ToString();
+ return errorStringBuilder.ToString().TrimStart(Environment.NewLine.ToCharArray());
}
///
@@ -79,5 +79,14 @@ namespace Tgstation.Server.Host.Core
}
catch (InvalidOperationException) { }
}
+
+ public void SetHighPriority()
+ {
+ try
+ {
+ handle.PriorityClass = System.Diagnostics.ProcessPriorityClass.AboveNormal;
+ }
+ catch (InvalidOperationException) { }
+ }
}
}
diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj
index b25b2b43de..fa8a4573ea 100644
--- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj
+++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj
@@ -20,7 +20,7 @@
-
+
diff --git a/tools/TGS.postman_collection.json b/tools/TGS.postman_collection.json
index 4c6ae4699f..c7f7374670 100644
--- a/tools/TGS.postman_collection.json
+++ b/tools/TGS.postman_collection.json
@@ -1,6 +1,6 @@
{
"info": {
- "_postman_id": "6defe202-821a-488f-b8fe-e4017992655f",
+ "_postman_id": "b7e61e38-6891-473e-8ab4-869e5cf41a96",
"name": "TGS",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
@@ -1254,7 +1254,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\n\t\"userId\": 1,\n\t\"byondRights\": 4294967294,\n\t\"dreamDaemonRights\": 4294967294,\n\t\"dreamMakerRights\": 4294967294,\n\t\"repositoryRights\": 4294967294\n\t\"chatBotRights\": 4294967294,\n\t\"configurationRights\": 4294967294\n}"
+ "raw": "{\n\t\"userId\": 1,\n\t\"byondRights\": 4294967295,\n\t\"dreamDaemonRights\": 4294967295,\n\t\"dreamMakerRights\": 4294967295,\n\t\"repositoryRights\": 4294967295\n\t\"chatBotRights\": 4294967295,\n\t\"configurationRights\": 4294967295\n}"
},
"url": {
"raw": "localhost:5000/InstanceUser",
@@ -1297,7 +1297,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\n\t\"userId\": 1,\n\t\"byondRights\": 4294967294,\n\t\"dreamDaemonRights\": 4294967294,\n\t\"dreamMakerRights\": 4294967294,\n\t\"repositoryRights\": 4294967294,\n\t\"chatBotRights\": 4294967294,\n\t\"configurationRights\": 4294967294\n}"
+ "raw": "{\n\t\"userId\": 1,\n\t\"byondRights\": 4294967295,\n\t\"dreamDaemonRights\": 4294967295,\n\t\"dreamMakerRights\": 4294967295,\n\t\"repositoryRights\": 4294967295,\n\t\"chatBotRights\": 4294967295,\n\t\"configurationRights\": 4294967295\n}"
},
"url": {
"raw": "localhost:5000/InstanceUser",
@@ -1901,7 +1901,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\n\t\"updateFromOrigin\": true,\n\t\"reference\": \"master\",\n\t\"newTestMerges\": [\n\t\t{\n\t\t\t\"number\": 39147,\n\t\t\t\"comment\": \"electric boogaloo\"\n\t\t}\n\t\t]\n}"
+ "raw": "{\n\t\"updateFromOrigin\": true,\n\t\"reference\": \"master\",\n\t\"newTestMerges\": [\n\t\t{\n\t\t\t\"number\": 39771,\n\t\t\t\"comment\": \"needful for debugging\"\n\t\t},\n\t\t{\n\t\t\t\"number\": 39777,\n\t\t\t\"comment\": \"also needful\"\n\t\t},\n\t\t{\n\t\t\t\"number\": 39778\n\t\t}\n\t\t]\n}"
},
"url": {
"raw": "localhost:5000/Repository",
@@ -2717,6 +2717,49 @@
},
"response": []
},
+ {
+ "name": "Read",
+ "request": {
+ "method": "GET",
+ "header": [
+ {
+ "key": "Accept",
+ "value": "application/json"
+ },
+ {
+ "key": "User-Agent",
+ "value": "Postman/1.0"
+ },
+ {
+ "key": "Api",
+ "value": "Tgstation.Server.Api/4.0.0.0"
+ },
+ {
+ "key": "Content-Type",
+ "value": "application/json"
+ },
+ {
+ "key": "Instance",
+ "value": "1"
+ }
+ ],
+ "body": {
+ "mode": "raw",
+ "raw": "{}"
+ },
+ "url": {
+ "raw": "localhost:5000/DreamDaemon",
+ "host": [
+ "localhost"
+ ],
+ "port": "5000",
+ "path": [
+ "DreamDaemon"
+ ]
+ }
+ },
+ "response": []
+ },
{
"name": "Stop",
"request": {
diff --git a/v4_prototype_TODO.txt b/v4_prototype_TODO.txt
index 572d75b123..641f358e0e 100644
--- a/v4_prototype_TODO.txt
+++ b/v4_prototype_TODO.txt
@@ -1,3 +1,6 @@
Verify the byond cache folder location on linux
Test watchdog
+
+Only show user name and ID when serializing to API
+In fact remove IApiConvertable<> altogether, it's not required by anything
\ No newline at end of file