diff --git a/src/Tgstation.Server.Api/Models/Internal/DreamDaemonLaunchParameters.cs b/src/Tgstation.Server.Api/Models/Internal/DreamDaemonLaunchParameters.cs
index 56c4c758b3..f30f4b296d 100644
--- a/src/Tgstation.Server.Api/Models/Internal/DreamDaemonLaunchParameters.cs
+++ b/src/Tgstation.Server.Api/Models/Internal/DreamDaemonLaunchParameters.cs
@@ -25,20 +25,21 @@ namespace Tgstation.Server.Api.Models.Internal
/// The first port uses. This should be the publically advertised port
///
[Required]
- [Range(1, 65535)]
+ [Range(1, UInt16.MaxValue)]
public ushort? PrimaryPort { get; set; }
///
/// The second port uses
///
[Required]
- [Range(1, 65535)]
+ [Range(1, UInt16.MaxValue)]
public ushort? SecondaryPort { get; set; }
///
/// The DreamDaemon startup timeout in seconds
///
[Required]
+ [Range(1, UInt32.MaxValue)]
public uint? StartupTimeout { get; set; }
///
@@ -47,6 +48,13 @@ namespace Tgstation.Server.Api.Models.Internal
[Required]
public uint? HeartbeatSeconds { get; set; }
+ ///
+ /// The timeout for sending and receiving BYOND topics in milliseconds.
+ ///
+ [Required]
+ [Range(1, UInt32.MaxValue)]
+ public uint? TopicRequestTimeout { get; set; }
+
///
/// Check if we match a given set of . is excluded.
///
@@ -56,6 +64,7 @@ namespace Tgstation.Server.Api.Models.Internal
AllowWebClient == (otherParameters?.AllowWebClient ?? throw new ArgumentNullException(nameof(otherParameters)))
&& SecurityLevel == otherParameters.SecurityLevel
&& PrimaryPort == otherParameters.PrimaryPort
- && SecondaryPort == otherParameters.SecondaryPort; // We intentionally don't check StartupTimeout or heartbeat seconds as it doesn't matter in terms of the watchdog
+ && SecondaryPort == otherParameters.SecondaryPort
+ && TopicRequestTimeout == otherParameters.TopicRequestTimeout; // We intentionally don't check StartupTimeout or heartbeat seconds as it doesn't matter in terms of the watchdog
}
}
\ No newline at end of file
diff --git a/src/Tgstation.Server.Api/Rights/DreamDaemonRights.cs b/src/Tgstation.Server.Api/Rights/DreamDaemonRights.cs
index fd4c53f641..083c7d4229 100644
--- a/src/Tgstation.Server.Api/Rights/DreamDaemonRights.cs
+++ b/src/Tgstation.Server.Api/Rights/DreamDaemonRights.cs
@@ -82,5 +82,10 @@ namespace Tgstation.Server.Api.Rights
/// User can create DreamDaemon process dumps.
///
CreateDump = 8192,
+
+ ///
+ /// User can change .
+ ///
+ SetTopicTimeout = 16384,
}
}
diff --git a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs
index 3a2eb928a0..1c5bc4ffd7 100644
--- a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs
+++ b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs
@@ -208,7 +208,8 @@ namespace Tgstation.Server.Host.Components.Deployment
AllowWebClient = false,
PrimaryPort = portToUse,
SecurityLevel = securityLevel,
- StartupTimeout = timeout
+ StartupTimeout = timeout,
+ TopicRequestTimeout = 0 // not used
};
var dirA = ioManager.ConcatPath(job.DirectoryName.ToString(), ADirectoryName);
diff --git a/src/Tgstation.Server.Host/Components/InstanceFactory.cs b/src/Tgstation.Server.Host/Components/InstanceFactory.cs
index cad5c38fa7..4e170b7b9a 100644
--- a/src/Tgstation.Server.Host/Components/InstanceFactory.cs
+++ b/src/Tgstation.Server.Host/Components/InstanceFactory.cs
@@ -1,5 +1,4 @@
-using Byond.TopicSender;
-using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging;
using System;
using System.Threading;
using System.Threading.Tasks;
@@ -45,9 +44,9 @@ namespace Tgstation.Server.Host.Components
readonly ILoggerFactory loggerFactory;
///
- /// The for the
+ /// The for the
///
- readonly ITopicClient byondTopicSender;
+ readonly ITopicClientFactory topicClientFactory;
///
/// The for the
@@ -131,7 +130,7 @@ namespace Tgstation.Server.Host.Components
/// The value of
/// The value of
/// The value of
- /// The value of
+ /// The value of
/// The value of
/// The value of
/// The value of
@@ -152,7 +151,7 @@ namespace Tgstation.Server.Host.Components
IDatabaseContextFactory databaseContextFactory,
IAssemblyInformationProvider assemblyInformationProvider,
ILoggerFactory loggerFactory,
- ITopicClient byondTopicSender,
+ ITopicClientFactory topicClientFactory,
ICryptographySuite cryptographySuite,
ISynchronousIOManager synchronousIOManager,
ISymlinkFactory symlinkFactory,
@@ -173,7 +172,7 @@ namespace Tgstation.Server.Host.Components
this.databaseContextFactory = databaseContextFactory ?? throw new ArgumentNullException(nameof(databaseContextFactory));
this.assemblyInformationProvider = assemblyInformationProvider ?? throw new ArgumentNullException(nameof(assemblyInformationProvider));
this.loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));
- this.byondTopicSender = byondTopicSender ?? throw new ArgumentNullException(nameof(byondTopicSender));
+ this.topicClientFactory = topicClientFactory ?? throw new ArgumentNullException(nameof(topicClientFactory));
this.cryptographySuite = cryptographySuite ?? throw new ArgumentNullException(nameof(cryptographySuite));
this.synchronousIOManager = synchronousIOManager ?? throw new ArgumentNullException(nameof(synchronousIOManager));
this.symlinkFactory = symlinkFactory ?? throw new ArgumentNullException(nameof(symlinkFactory));
@@ -226,7 +225,7 @@ namespace Tgstation.Server.Host.Components
var sessionControllerFactory = new SessionControllerFactory(
processExecutor,
byond,
- byondTopicSender,
+ topicClientFactory,
cryptographySuite,
assemblyInformationProvider,
gameIoManager,
diff --git a/src/Tgstation.Server.Host/Components/Session/DualReattachInformation.cs b/src/Tgstation.Server.Host/Components/Session/DualReattachInformation.cs
index 2732935299..486bc1e85c 100644
--- a/src/Tgstation.Server.Host/Components/Session/DualReattachInformation.cs
+++ b/src/Tgstation.Server.Host/Components/Session/DualReattachInformation.cs
@@ -20,6 +20,11 @@ namespace Tgstation.Server.Host.Components.Session
///
public ReattachInformation Bravo { get; set; }
+ ///
+ /// The timeout used for topic request.
+ ///
+ public TimeSpan TopicRequestTimeout { get; set; }
+
///
/// Construct a
///
diff --git a/src/Tgstation.Server.Host/Components/Session/ISessionControllerFactory.cs b/src/Tgstation.Server.Host/Components/Session/ISessionControllerFactory.cs
index 452216cb6c..5a9d7d479e 100644
--- a/src/Tgstation.Server.Host/Components/Session/ISessionControllerFactory.cs
+++ b/src/Tgstation.Server.Host/Components/Session/ISessionControllerFactory.cs
@@ -1,4 +1,5 @@
-using System.Threading;
+using System;
+using System.Threading;
using System.Threading.Tasks;
using Tgstation.Server.Api.Models.Internal;
using Tgstation.Server.Host.Components.Byond;
@@ -35,10 +36,12 @@ namespace Tgstation.Server.Host.Components.Session
/// Create a from an existing DreamDaemon instance
///
/// The to use
+ /// The timeout for sending topic requests.
/// The for the operation
/// A resulting in a new on success or on failure to reattach
Task Reattach(
ReattachInformation reattachInformation,
+ TimeSpan topicRequestTimeout,
CancellationToken cancellationToken);
///
diff --git a/src/Tgstation.Server.Host/Components/Session/ITopicClientFactory.cs b/src/Tgstation.Server.Host/Components/Session/ITopicClientFactory.cs
new file mode 100644
index 0000000000..2a02a0170f
--- /dev/null
+++ b/src/Tgstation.Server.Host/Components/Session/ITopicClientFactory.cs
@@ -0,0 +1,18 @@
+using Byond.TopicSender;
+using System;
+
+namespace Tgstation.Server.Host.Components.Session
+{
+ ///
+ /// Factory for s
+ ///
+ interface ITopicClientFactory
+ {
+ ///
+ /// Create a .
+ ///
+ /// The request timeout.
+ /// A new .
+ ITopicClient CreateTopicClient(TimeSpan timeout);
+ }
+}
diff --git a/src/Tgstation.Server.Host/Components/Session/ReattachInfoHandler.cs b/src/Tgstation.Server.Host/Components/Session/ReattachInfoHandler.cs
index b7d377ef8a..9185132b7c 100644
--- a/src/Tgstation.Server.Host/Components/Session/ReattachInfoHandler.cs
+++ b/src/Tgstation.Server.Host/Components/Session/ReattachInfoHandler.cs
@@ -94,11 +94,24 @@ namespace Tgstation.Server.Host.Components.Session
public async Task Load(CancellationToken cancellationToken)
{
Models.DualReattachInformation result = null;
+ TimeSpan? topicTimeout = null;
await databaseContextFactory.UseContext(async (db) =>
{
- var instance = await db.Instances
+ IQueryable InstanceQuery() => db.Instances
.AsQueryable()
- .Where(x => x.Id == metadata.Id)
+ .Where(x => x.Id == metadata.Id);
+
+ var timeoutMilliseconds = await InstanceQuery()
+ .Select(x => x.DreamDaemonSettings.TopicRequestTimeout)
+ .FirstOrDefaultAsync(cancellationToken)
+ .ConfigureAwait(false);
+
+ if (timeoutMilliseconds == default)
+ return;
+
+ topicTimeout = TimeSpan.FromMilliseconds(timeoutMilliseconds.Value);
+
+ var instance = await InstanceQuery()
.Include(x => x.WatchdogReattachInformation).ThenInclude(x => x.Alpha).ThenInclude(x => x.CompileJob)
.Include(x => x.WatchdogReattachInformation).ThenInclude(x => x.Bravo).ThenInclude(x => x.CompileJob)
.FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
@@ -121,7 +134,14 @@ namespace Tgstation.Server.Host.Components.Session
: Task.FromResult(null);
var bravoDmbTask = GetDmbForReattachInfo(result.Bravo);
- var info = new DualReattachInformation(result, await GetDmbForReattachInfo(result.Alpha).ConfigureAwait(false), await bravoDmbTask.ConfigureAwait(false));
+ var info = new DualReattachInformation(
+ result,
+ await GetDmbForReattachInfo(result.Alpha).ConfigureAwait(false),
+ await bravoDmbTask.ConfigureAwait(false))
+ {
+ TopicRequestTimeout = topicTimeout.Value
+ };
+
logger.LogDebug("Reattach information loaded: {0}", info);
return info;
}
diff --git a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs
index b1861108dc..b03439f38b 100644
--- a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs
+++ b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs
@@ -1,5 +1,4 @@
-using Byond.TopicSender;
-using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging;
using System;
using System.Globalization;
using System.Linq;
@@ -38,9 +37,9 @@ namespace Tgstation.Server.Host.Components.Session
readonly IByondManager byond;
///
- /// The for the
+ /// The for the
///
- readonly ITopicClient byondTopicSender;
+ readonly ITopicClientFactory topicClientFactory;
///
/// The for the
@@ -136,7 +135,7 @@ namespace Tgstation.Server.Host.Components.Session
///
/// The value of
/// The value of
- /// The value of
+ /// The value of .
/// The value of
/// The value of
/// The value of
@@ -151,7 +150,7 @@ namespace Tgstation.Server.Host.Components.Session
public SessionControllerFactory(
IProcessExecutor processExecutor,
IByondManager byond,
- ITopicClient byondTopicSender,
+ ITopicClientFactory topicClientFactory,
ICryptographySuite cryptographySuite,
IAssemblyInformationProvider assemblyInformationProvider,
IIOManager ioManager,
@@ -166,7 +165,7 @@ namespace Tgstation.Server.Host.Components.Session
{
this.processExecutor = processExecutor ?? throw new ArgumentNullException(nameof(processExecutor));
this.byond = byond ?? throw new ArgumentNullException(nameof(byond));
- this.byondTopicSender = byondTopicSender ?? throw new ArgumentNullException(nameof(byondTopicSender));
+ this.topicClientFactory = topicClientFactory ?? throw new ArgumentNullException(nameof(topicClientFactory));
this.cryptographySuite = cryptographySuite ?? throw new ArgumentNullException(nameof(cryptographySuite));
this.assemblyInformationProvider = assemblyInformationProvider ?? throw new ArgumentNullException(nameof(assemblyInformationProvider));
this.instance = instance ?? throw new ArgumentNullException(nameof(instance));
@@ -227,6 +226,10 @@ namespace Tgstation.Server.Host.Components.Session
var accessIdentifier = cryptographySuite.GetSecureString();
+ var byondTopicSender = topicClientFactory.CreateTopicClient(
+ TimeSpan.FromMilliseconds(
+ launchParameters.TopicRequestTimeout.Value));
+
// set command line options
// more sanitization here cause it uses the same scheme
var parameters = $"{DMApiConstants.ParamApiVersion}={byondTopicSender.SanitizeString(DMApiConstants.Version.Semver().ToString())}&{byondTopicSender.SanitizeString(DMApiConstants.ParamServerPort)}={serverPortProvider.HttpApiPort}&{byondTopicSender.SanitizeString(DMApiConstants.ParamAccessIdentifier)}={byondTopicSender.SanitizeString(accessIdentifier)}";
@@ -365,11 +368,13 @@ namespace Tgstation.Server.Host.Components.Session
///
public async Task Reattach(
ReattachInformation reattachInformation,
+ TimeSpan topicRequestTimeout,
CancellationToken cancellationToken)
{
if (reattachInformation == null)
throw new ArgumentNullException(nameof(reattachInformation));
+ var byondTopicSender = topicClientFactory.CreateTopicClient(topicRequestTimeout);
var chatTrackingContext = chat.CreateTrackingContext();
try
{
diff --git a/src/Tgstation.Server.Host/Components/Session/TopicClientFactory.cs b/src/Tgstation.Server.Host/Components/Session/TopicClientFactory.cs
new file mode 100644
index 0000000000..0ffa57542d
--- /dev/null
+++ b/src/Tgstation.Server.Host/Components/Session/TopicClientFactory.cs
@@ -0,0 +1,36 @@
+using Byond.TopicSender;
+using Microsoft.Extensions.Logging;
+using System;
+
+namespace Tgstation.Server.Host.Components.Session
+{
+ ///
+ sealed class TopicClientFactory : ITopicClientFactory
+ {
+ ///
+ /// The for created s.
+ ///
+ readonly ILogger logger;
+
+ ///
+ /// Initializes a new instance of the .
+ ///
+ /// The value of .
+ public TopicClientFactory(ILogger logger)
+ {
+ this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
+ }
+
+ ///
+ public ITopicClient CreateTopicClient(TimeSpan timeout)
+ => new TopicClient(
+ new SocketParameters
+ {
+ ConnectTimeout = timeout,
+ DisconnectTimeout = timeout,
+ ReceiveTimeout = timeout,
+ SendTimeout = timeout
+ },
+ logger);
+ }
+}
diff --git a/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs
index 63cdb20557..e9e5083e3f 100644
--- a/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs
+++ b/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs
@@ -253,11 +253,11 @@ namespace Tgstation.Server.Host.Components.Watchdog
cancellationToken);
}
else
- serverLaunchTask = SessionControllerFactory.Reattach(serverToReattach, cancellationToken);
+ serverLaunchTask = SessionControllerFactory.Reattach(serverToReattach, reattachInfo.TopicRequestTimeout, cancellationToken);
bool thereIsAnInactiveServerToKill = serverToKill != null;
if (thereIsAnInactiveServerToKill)
- inactiveReattachTask = SessionControllerFactory.Reattach(serverToKill, cancellationToken);
+ inactiveReattachTask = SessionControllerFactory.Reattach(serverToKill, reattachInfo.TopicRequestTimeout, cancellationToken);
else
inactiveReattachTask = Task.FromResult(null);
diff --git a/src/Tgstation.Server.Host/Components/Watchdog/ExperimentalWatchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/ExperimentalWatchdog.cs
index 95d2fc12b2..320ca1a96c 100644
--- a/src/Tgstation.Server.Host/Components/Watchdog/ExperimentalWatchdog.cs
+++ b/src/Tgstation.Server.Host/Components/Watchdog/ExperimentalWatchdog.cs
@@ -470,7 +470,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
false,
cancellationToken);
else
- alphaServerTask = SessionControllerFactory.Reattach(reattachInfo.Alpha, cancellationToken);
+ alphaServerTask = SessionControllerFactory.Reattach(reattachInfo.Alpha, reattachInfo.TopicRequestTimeout, cancellationToken);
// retrieve the session controller
var startTime = DateTimeOffset.Now;
@@ -499,7 +499,10 @@ namespace Tgstation.Server.Host.Components.Watchdog
cancellationToken)
.ConfigureAwait(false);
else
- bravoServer = await SessionControllerFactory.Reattach(reattachInfo.Bravo, cancellationToken).ConfigureAwait(false);
+ bravoServer = await SessionControllerFactory.Reattach(
+ reattachInfo.Bravo,
+ reattachInfo.TopicRequestTimeout,
+ cancellationToken).ConfigureAwait(false);
// failed reattaches will return null
bravoServer?.SetHighPriority();
diff --git a/src/Tgstation.Server.Host/Configuration/DatabaseConfiguration.cs b/src/Tgstation.Server.Host/Configuration/DatabaseConfiguration.cs
index 92fd68237d..88b634beae 100644
--- a/src/Tgstation.Server.Host/Configuration/DatabaseConfiguration.cs
+++ b/src/Tgstation.Server.Host/Configuration/DatabaseConfiguration.cs
@@ -6,7 +6,7 @@ namespace Tgstation.Server.Host.Configuration
///
/// Configuration options for the
///
- sealed class DatabaseConfiguration
+ public sealed class DatabaseConfiguration
{
///
/// The key for the the resides in
diff --git a/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs b/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs
index 39c4ac068c..4f617cdd33 100644
--- a/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs
+++ b/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs
@@ -37,12 +37,12 @@ namespace Tgstation.Server.Host.Configuration
///
/// The default value for
///
- const int DefaultByondTopicTimeout = 5000;
+ const uint DefaultByondTopicTimeout = 5000;
///
/// The default value for
///
- const int DefaultRestartTimeout = 60000;
+ const uint DefaultRestartTimeout = 60000;
///
/// The port the TGS API listens on.
@@ -63,12 +63,12 @@ namespace Tgstation.Server.Host.Configuration
///
/// The timeout in milliseconds for sending and receiving topics to/from DreamDaemon. Note that a single topic exchange can take up to twice this value
///
- public int ByondTopicTimeout { get; set; } = DefaultByondTopicTimeout;
+ public uint ByondTopicTimeout { get; set; } = DefaultByondTopicTimeout;
///
/// The timeout milliseconds for restarting the server
///
- public int RestartTimeout { get; set; } = DefaultRestartTimeout;
+ public uint RestartTimeout { get; set; } = DefaultRestartTimeout;
///
/// If the should be used.
diff --git a/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs b/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs
index 1e03b0163d..a2daa40649 100644
--- a/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs
+++ b/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs
@@ -137,6 +137,7 @@ namespace Tgstation.Server.Host.Controllers
result.SoftShutdown = rstate == RebootState.Shutdown;
result.StartupTimeout = settings.StartupTimeout.Value;
result.HeartbeatSeconds = settings.HeartbeatSeconds.Value;
+ result.TopicRequestTimeout = settings.TopicRequestTimeout.Value;
}
if (revision)
@@ -175,7 +176,17 @@ namespace Tgstation.Server.Host.Controllers
/// Settings applied successfully.
/// The database entity for the requested instance could not be retrieved. The instance was likely detached.
[HttpPost]
- [TgsAuthorize(DreamDaemonRights.SetAutoStart | DreamDaemonRights.SetPorts | DreamDaemonRights.SetSecurity | DreamDaemonRights.SetWebClient | DreamDaemonRights.SoftRestart | DreamDaemonRights.SoftShutdown | DreamDaemonRights.Start | DreamDaemonRights.SetStartupTimeout | DreamDaemonRights.SetHeartbeatInterval)]
+ [TgsAuthorize(
+ DreamDaemonRights.SetAutoStart
+ | DreamDaemonRights.SetPorts
+ | DreamDaemonRights.SetSecurity
+ | DreamDaemonRights.SetWebClient
+ | DreamDaemonRights.SoftRestart
+ | DreamDaemonRights.SoftShutdown
+ | DreamDaemonRights.Start
+ | DreamDaemonRights.SetStartupTimeout
+ | DreamDaemonRights.SetHeartbeatInterval
+ | DreamDaemonRights.SetTopicTimeout)]
[ProducesResponseType(typeof(DreamDaemon), 200)]
[ProducesResponseType(typeof(ErrorMessage), 410)]
#pragma warning disable CA1502 // TODO: Decomplexify
@@ -237,7 +248,8 @@ namespace Tgstation.Server.Host.Controllers
|| (model.SoftRestart.HasValue && !AuthenticationContext.InstanceUser.DreamDaemonRights.Value.HasFlag(DreamDaemonRights.SoftRestart))
|| (model.SoftShutdown.HasValue && !AuthenticationContext.InstanceUser.DreamDaemonRights.Value.HasFlag(DreamDaemonRights.SoftShutdown))
|| CheckModified(x => x.StartupTimeout, DreamDaemonRights.SetStartupTimeout)
- || CheckModified(x => x.HeartbeatSeconds, DreamDaemonRights.SetHeartbeatInterval))
+ || CheckModified(x => x.HeartbeatSeconds, DreamDaemonRights.SetHeartbeatInterval)
+ || CheckModified(x => x.TopicRequestTimeout, DreamDaemonRights.SetTopicTimeout))
return Forbid();
if (current.PrimaryPort == current.SecondaryPort)
diff --git a/src/Tgstation.Server.Host/Controllers/InstanceController.cs b/src/Tgstation.Server.Host/Controllers/InstanceController.cs
index 5efd4ed1c4..0b93c494e4 100644
--- a/src/Tgstation.Server.Host/Controllers/InstanceController.cs
+++ b/src/Tgstation.Server.Host/Controllers/InstanceController.cs
@@ -248,7 +248,8 @@ namespace Tgstation.Server.Host.Controllers
SecondaryPort = 1338,
SecurityLevel = DreamDaemonSecurity.Safe,
StartupTimeout = 60,
- HeartbeatSeconds = 60
+ HeartbeatSeconds = 60,
+ TopicRequestTimeout = generalConfiguration.ByondTopicTimeout
},
DreamMakerSettings = new DreamMakerSettings
{
diff --git a/src/Tgstation.Server.Host/Core/Application.cs b/src/Tgstation.Server.Host/Core/Application.cs
index df047e95ad..87b73cd372 100644
--- a/src/Tgstation.Server.Host/Core/Application.cs
+++ b/src/Tgstation.Server.Host/Core/Application.cs
@@ -1,5 +1,4 @@
-using Byond.TopicSender;
-using Cyberboss.AspNetCore.AsyncInitializer;
+using Cyberboss.AspNetCore.AsyncInitializer;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Cors.Infrastructure;
@@ -18,7 +17,6 @@ using Serilog.Formatting.Display;
using System;
using System.Globalization;
using System.IdentityModel.Tokens.Jwt;
-using System.Reflection;
using System.Threading.Tasks;
using Tgstation.Server.Api;
using Tgstation.Server.Api.Models;
@@ -29,6 +27,7 @@ using Tgstation.Server.Host.Components.Chat.Providers;
using Tgstation.Server.Host.Components.Interop.Bridge;
using Tgstation.Server.Host.Components.Interop.Converters;
using Tgstation.Server.Host.Components.Repository;
+using Tgstation.Server.Host.Components.Session;
using Tgstation.Server.Host.Components.Watchdog;
using Tgstation.Server.Host.Configuration;
using Tgstation.Server.Host.Database;
@@ -208,14 +207,7 @@ namespace Tgstation.Server.Host.Core
void AddTypedContext() where TContext : DatabaseContext
{
- // HACK HACK HACK HACK HACK
- const string ConfigureMethodName = nameof(SqlServerDatabaseContext.ConfigureWith);
- var configureFunction = typeof(TContext).GetMethod(
- ConfigureMethodName,
- BindingFlags.Public | BindingFlags.Static);
-
- if (configureFunction == null)
- throw new InvalidOperationException($"Context type {typeof(TContext).FullName} missing static {ConfigureMethodName} function!");
+ var configureAction = DatabaseContext.GetConfigureAction();
services.AddDbContextPool((serviceProvider, builder) =>
{
@@ -224,7 +216,7 @@ namespace Tgstation.Server.Host.Core
var databaseConfigOptions = serviceProvider.GetRequiredService>();
var databaseConfig = databaseConfigOptions.Value ?? throw new InvalidOperationException("DatabaseConfiguration missing!");
- configureFunction.Invoke(null, new object[] { builder, databaseConfig });
+ configureAction(builder, databaseConfig);
});
services.AddScoped(x => x.GetRequiredService());
}
@@ -300,14 +292,7 @@ namespace Tgstation.Server.Host.Core
services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
- services.AddSingleton();
- services.AddSingleton(new SocketParameters
- {
- ReceiveTimeout = TimeSpan.FromMilliseconds(postSetupServices.GeneralConfiguration.ByondTopicTimeout),
- SendTimeout = TimeSpan.FromMilliseconds(postSetupServices.GeneralConfiguration.ByondTopicTimeout),
- ConnectTimeout = TimeSpan.FromMilliseconds(postSetupServices.GeneralConfiguration.ByondTopicTimeout),
- DisconnectTimeout = TimeSpan.FromMilliseconds(postSetupServices.GeneralConfiguration.ByondTopicTimeout)
- });
+ services.AddSingleton();
// configure component services
services.AddSingleton();
diff --git a/src/Tgstation.Server.Host/Database/DatabaseContext.cs b/src/Tgstation.Server.Host/Database/DatabaseContext.cs
index 17cfaa3323..c9452aece5 100644
--- a/src/Tgstation.Server.Host/Database/DatabaseContext.cs
+++ b/src/Tgstation.Server.Host/Database/DatabaseContext.cs
@@ -6,6 +6,7 @@ using Microsoft.Extensions.Logging;
using System;
using System.Globalization;
using System.Linq;
+using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Tgstation.Server.Host.Configuration;
@@ -204,6 +205,26 @@ namespace Tgstation.Server.Host.Database
///
readonly IDatabaseCollection watchdogReattachInformationsCollection;
+ ///
+ /// Gets the configure action for a given .
+ ///
+ /// The parent class to configure with.
+ /// A configure .
+ public static Action GetConfigureAction()
+ where TDatabaseContext : DatabaseContext
+ {
+ // HACK HACK HACK HACK HACK
+ const string ConfigureMethodName = nameof(SqlServerDatabaseContext.ConfigureWith);
+ var configureFunction = typeof(TDatabaseContext).GetMethod(
+ ConfigureMethodName,
+ BindingFlags.Public | BindingFlags.Static);
+
+ if (configureFunction == null)
+ throw new InvalidOperationException($"Context type {typeof(TDatabaseContext).FullName} missing static {ConfigureMethodName} function!");
+
+ return (optionsBuilder, config) => configureFunction.Invoke(null, new object[] { optionsBuilder, config });
+ }
+
///
/// Construct a
///
@@ -330,6 +351,24 @@ namespace Tgstation.Server.Host.Database
if (version < new Version(4, 1, 0))
throw new NotSupportedException("Cannot migrate below version 4.1.0!");
+ if(version < new Version(4, 4, 0))
+ switch (currentDatabaseType)
+ {
+ case DatabaseType.MariaDB:
+ case DatabaseType.MySql:
+ targetMigration = nameof(MYFixForeignKey);
+ break;
+ case DatabaseType.PostgresSql:
+ targetMigration = nameof(PGCreate);
+ break;
+ case DatabaseType.SqlServer:
+ case DatabaseType.Sqlite:
+ targetMigration = nameof(MSRemoveSoftColumns);
+ break;
+ default:
+ throw new ArgumentException($"Invalid DatabaseType: {currentDatabaseType}", nameof(currentDatabaseType));
+ }
+
if (version < new Version(4, 2, 0))
targetMigration = currentDatabaseType == DatabaseType.Sqlite ? nameof(SLRebuild) : nameof(MSFixCascadingDelete);
diff --git a/src/Tgstation.Server.Host/Database/DatabaseSeeder.cs b/src/Tgstation.Server.Host/Database/DatabaseSeeder.cs
index 4bbc995197..0e97d98f6c 100644
--- a/src/Tgstation.Server.Host/Database/DatabaseSeeder.cs
+++ b/src/Tgstation.Server.Host/Database/DatabaseSeeder.cs
@@ -10,6 +10,7 @@ using Tgstation.Server.Host.Configuration;
using Tgstation.Server.Host.Models;
using Tgstation.Server.Host.Security;
using Tgstation.Server.Host.System;
+using Z.EntityFramework.Plus;
namespace Tgstation.Server.Host.Database
{
@@ -36,6 +37,11 @@ namespace Tgstation.Server.Host.Database
///
readonly ILogger logger;
+ ///
+ /// The for the .
+ ///
+ readonly GeneralConfiguration generalConfiguration;
+
///
/// The for the .
///
@@ -46,12 +52,14 @@ namespace Tgstation.Server.Host.Database
///
/// The value of
/// The value of .
+ /// The containing the value of .
/// The containing the value of .
/// The value of
/// The value of .
public DatabaseSeeder(
ICryptographySuite cryptographySuite,
IPlatformIdentifier platformIdentifier,
+ IOptions generalConfigurationOptions,
IOptions databaseConfigurationOptions,
ILogger databaseLogger,
ILogger logger)
@@ -59,6 +67,7 @@ namespace Tgstation.Server.Host.Database
this.cryptographySuite = cryptographySuite ?? throw new ArgumentNullException(nameof(cryptographySuite));
this.platformIdentifier = platformIdentifier ?? throw new ArgumentNullException(nameof(platformIdentifier));
databaseConfiguration = databaseConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(databaseConfigurationOptions));
+ generalConfiguration = generalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(generalConfigurationOptions));
this.databaseLogger = databaseLogger ?? throw new ArgumentNullException(nameof(databaseLogger));
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
@@ -124,6 +133,22 @@ namespace Tgstation.Server.Host.Database
instance.Path = instance.Path.Replace('\\', '/');
}
+ // Update settings from config
+ var rowsUpdated = await databaseContext
+ .DreamDaemonSettings
+ .AsQueryable()
+ .Where(x => x.TopicRequestTimeout == 0)
+ .UpdateAsync(
+ settings => new DreamDaemonSettings { TopicRequestTimeout = generalConfiguration.ByondTopicTimeout },
+ cancellationToken)
+ .ConfigureAwait(false);
+
+ if (rowsUpdated > 0)
+ logger.LogInformation(
+ "Updated {0} instances to use database backed BYOND topic timeouts from configuration setting of {1}",
+ rowsUpdated,
+ generalConfiguration.ByondTopicTimeout);
+
await databaseContext.Save(cancellationToken).ConfigureAwait(false);
}
diff --git a/src/Tgstation.Server.Host/Database/Design/DesignTimeDbContextFactoryHelpers.cs b/src/Tgstation.Server.Host/Database/Design/DesignTimeDbContextFactoryHelpers.cs
index 98f71aeaaf..4d4f4411dd 100644
--- a/src/Tgstation.Server.Host/Database/Design/DesignTimeDbContextFactoryHelpers.cs
+++ b/src/Tgstation.Server.Host/Database/Design/DesignTimeDbContextFactoryHelpers.cs
@@ -1,4 +1,5 @@
-using Microsoft.Extensions.Options;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.Options;
using Tgstation.Server.Host.Configuration;
namespace Tgstation.Server.Host.Database.Design
@@ -11,10 +12,14 @@ namespace Tgstation.Server.Host.Database.Design
///
/// Get the for the
///
+ /// The to create for.
/// The .
/// The .
/// The for the
- public static IOptions GetDatabaseConfiguration(DatabaseType databaseType, string connectionString)
+ public static DbContextOptions CreateDatabaseContextOptions(
+ DatabaseType databaseType,
+ string connectionString)
+ where TDatabaseContext : DatabaseContext
{
var dbConfig = new DatabaseConfiguration
{
@@ -23,7 +28,12 @@ namespace Tgstation.Server.Host.Database.Design
ConnectionString = connectionString
};
- return Options.Create(dbConfig);
+ var optionsFac = new DbContextOptionsBuilder();
+ var configureAction = DatabaseContext.GetConfigureAction();
+
+ configureAction(optionsFac, dbConfig);
+
+ return optionsFac.Options;
}
}
}
diff --git a/src/Tgstation.Server.Host/Database/Design/MySqlDesignTimeDbContextFactory.cs b/src/Tgstation.Server.Host/Database/Design/MySqlDesignTimeDbContextFactory.cs
new file mode 100644
index 0000000000..448e3f3405
--- /dev/null
+++ b/src/Tgstation.Server.Host/Database/Design/MySqlDesignTimeDbContextFactory.cs
@@ -0,0 +1,18 @@
+using Microsoft.EntityFrameworkCore.Design;
+using Tgstation.Server.Host.Configuration;
+
+namespace Tgstation.Server.Host.Database.Design
+{
+ ///
+ /// for creating s.
+ ///
+ sealed class MySqlDesignTimeDbContextFactory : IDesignTimeDbContextFactory
+ {
+ ///
+ public MySqlDatabaseContext CreateDbContext(string[] args)
+ => new MySqlDatabaseContext(
+ DesignTimeDbContextFactoryHelpers.CreateDatabaseContextOptions(
+ DatabaseType.MariaDB,
+ "Server=127.0.0.1;User Id=root;Password=fake;Database=TGS_Design"));
+ }
+}
diff --git a/src/Tgstation.Server.Host/Database/Design/PostgresSqlDesignTimeDbContextFactory.cs b/src/Tgstation.Server.Host/Database/Design/PostgresSqlDesignTimeDbContextFactory.cs
new file mode 100644
index 0000000000..3cd399f919
--- /dev/null
+++ b/src/Tgstation.Server.Host/Database/Design/PostgresSqlDesignTimeDbContextFactory.cs
@@ -0,0 +1,18 @@
+using Microsoft.EntityFrameworkCore.Design;
+using Tgstation.Server.Host.Configuration;
+
+namespace Tgstation.Server.Host.Database.Design
+{
+ ///
+ /// for creating s.
+ ///
+ sealed class PostgresSqlDesignTimeDbContextFactory : IDesignTimeDbContextFactory
+ {
+ ///
+ public PostgresSqlDatabaseContext CreateDbContext(string[] args)
+ => new PostgresSqlDatabaseContext(
+ DesignTimeDbContextFactoryHelpers.CreateDatabaseContextOptions(
+ DatabaseType.PostgresSql,
+ "Application Name=tgstation-server;Host=127.0.0.1;Password=fake;Username=postgres;Database=TGS_Design"));
+ }
+}
diff --git a/src/Tgstation.Server.Host/Database/Design/SqlServerDesignTimeDbContextFactory.cs b/src/Tgstation.Server.Host/Database/Design/SqlServerDesignTimeDbContextFactory.cs
new file mode 100644
index 0000000000..ba12ce48ff
--- /dev/null
+++ b/src/Tgstation.Server.Host/Database/Design/SqlServerDesignTimeDbContextFactory.cs
@@ -0,0 +1,18 @@
+using Microsoft.EntityFrameworkCore.Design;
+using Tgstation.Server.Host.Configuration;
+
+namespace Tgstation.Server.Host.Database.Design
+{
+ ///
+ /// for creating s.
+ ///
+ sealed class SqlServerDesignTimeDbContextFactory : IDesignTimeDbContextFactory
+ {
+ ///
+ public SqlServerDatabaseContext CreateDbContext(string[] args)
+ => new SqlServerDatabaseContext(
+ DesignTimeDbContextFactoryHelpers.CreateDatabaseContextOptions(
+ DatabaseType.SqlServer,
+ "Data Source=fake;Initial Catalog=TGS_Design;Integrated Security=True;Application Name=tgstation-server"));
+ }
+}
diff --git a/src/Tgstation.Server.Host/Database/Design/SqliteDesignTimeDbContextFactory.cs b/src/Tgstation.Server.Host/Database/Design/SqliteDesignTimeDbContextFactory.cs
index 330cbc39f3..5344c0f911 100644
--- a/src/Tgstation.Server.Host/Database/Design/SqliteDesignTimeDbContextFactory.cs
+++ b/src/Tgstation.Server.Host/Database/Design/SqliteDesignTimeDbContextFactory.cs
@@ -1,6 +1,4 @@
-using Microsoft.EntityFrameworkCore;
-using Microsoft.EntityFrameworkCore.Design;
-using Microsoft.Extensions.Logging;
+using Microsoft.EntityFrameworkCore.Design;
using Tgstation.Server.Host.Configuration;
namespace Tgstation.Server.Host.Database.Design
@@ -13,14 +11,11 @@ namespace Tgstation.Server.Host.Database.Design
///
public SqliteDatabaseContext CreateDbContext(string[] args)
{
- using var loggerFactory = new LoggerFactory();
- var config =
- DesignTimeDbContextFactoryHelpers.GetDatabaseConfiguration(
- DatabaseType.Sqlite,
- "Data Source=tgs_design.sqlite3;Mode=ReadWriteCreate");
- SqliteDatabaseContext.DesignTime = config.Value.DesignTime;
+ SqliteDatabaseContext.DesignTime = true;
return new SqliteDatabaseContext(
- new DbContextOptions());
+ DesignTimeDbContextFactoryHelpers.CreateDatabaseContextOptions(
+ DatabaseType.Sqlite,
+ "Data Source=tgs_design.sqlite3;Mode=ReadWriteCreate"));
}
}
}
diff --git a/src/Tgstation.Server.Host/Database/Migrations/20200516111712_PGCreate.cs b/src/Tgstation.Server.Host/Database/Migrations/20200516111712_PGCreate.cs
index d76ef1939f..10c42cce5d 100644
--- a/src/Tgstation.Server.Host/Database/Migrations/20200516111712_PGCreate.cs
+++ b/src/Tgstation.Server.Host/Database/Migrations/20200516111712_PGCreate.cs
@@ -5,7 +5,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace Tgstation.Server.Host.Database.Migrations
{
///
- /// Create initial schema for PostgreSQL.
+ /// Create initial schema for PostgresSQL.
///
public partial class PGCreate : Migration
{
diff --git a/src/Tgstation.Server.Host/Database/Migrations/20200616175424_MSTopicTimeout.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20200616175424_MSTopicTimeout.Designer.cs
new file mode 100644
index 0000000000..1c7a723fa3
--- /dev/null
+++ b/src/Tgstation.Server.Host/Database/Migrations/20200616175424_MSTopicTimeout.Designer.cs
@@ -0,0 +1,822 @@
+//
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace Tgstation.Server.Host.Database.Migrations
+{
+ [DbContext(typeof(SqlServerDatabaseContext))]
+ [Migration("20200616175424_MSTopicTimeout")]
+ partial class MSTopicTimeout
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "3.1.4")
+ .HasAnnotation("Relational:MaxIdentifierLength", 128)
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("ChannelLimit")
+ .HasColumnType("int");
+
+ b.Property("ConnectionString")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)")
+ .HasMaxLength(10000);
+
+ b.Property("Enabled")
+ .HasColumnType("bit");
+
+ b.Property("InstanceId")
+ .HasColumnType("bigint");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("nvarchar(100)")
+ .HasMaxLength(100);
+
+ b.Property("Provider")
+ .HasColumnType("int");
+
+ b.Property("ReconnectionInterval")
+ .HasColumnType("bigint");
+
+ b.HasKey("Id");
+
+ b.HasIndex("InstanceId", "Name")
+ .IsUnique();
+
+ b.ToTable("ChatBots");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.ChatChannel", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("ChatSettingsId")
+ .HasColumnType("bigint");
+
+ b.Property("DiscordChannelId")
+ .HasColumnType("decimal(20,0)");
+
+ b.Property("IrcChannel")
+ .HasColumnType("nvarchar(100)")
+ .HasMaxLength(100);
+
+ b.Property("IsAdminChannel")
+ .IsRequired()
+ .HasColumnType("bit");
+
+ b.Property("IsUpdatesChannel")
+ .IsRequired()
+ .HasColumnType("bit");
+
+ b.Property("IsWatchdogChannel")
+ .IsRequired()
+ .HasColumnType("bit");
+
+ b.Property("Tag")
+ .HasColumnType("nvarchar(max)")
+ .HasMaxLength(10000);
+
+ b.HasKey("Id");
+
+ b.HasIndex("ChatSettingsId", "DiscordChannelId")
+ .IsUnique()
+ .HasFilter("[DiscordChannelId] IS NOT NULL");
+
+ b.HasIndex("ChatSettingsId", "IrcChannel")
+ .IsUnique()
+ .HasFilter("[IrcChannel] IS NOT NULL");
+
+ b.ToTable("ChatChannels");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.CompileJob", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("ByondVersion")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("DMApiMajorVersion")
+ .HasColumnType("int");
+
+ b.Property("DMApiMinorVersion")
+ .HasColumnType("int");
+
+ b.Property("DMApiPatchVersion")
+ .HasColumnType("int");
+
+ b.Property("DirectoryName")
+ .IsRequired()
+ .HasColumnType("uniqueidentifier");
+
+ b.Property("DmeName")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("JobId")
+ .HasColumnType("bigint");
+
+ b.Property("MinimumSecurityLevel")
+ .HasColumnType("int");
+
+ b.Property("Output")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("RevisionInformationId")
+ .HasColumnType("bigint");
+
+ b.HasKey("Id");
+
+ b.HasIndex("DirectoryName");
+
+ b.HasIndex("JobId")
+ .IsUnique();
+
+ b.HasIndex("RevisionInformationId");
+
+ b.ToTable("CompileJobs");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.DreamDaemonSettings", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("AllowWebClient")
+ .IsRequired()
+ .HasColumnType("bit");
+
+ b.Property("AutoStart")
+ .IsRequired()
+ .HasColumnType("bit");
+
+ b.Property("HeartbeatSeconds")
+ .HasColumnType("bigint");
+
+ b.Property("InstanceId")
+ .HasColumnType("bigint");
+
+ b.Property("PrimaryPort")
+ .HasColumnType("int");
+
+ b.Property("SecondaryPort")
+ .HasColumnType("int");
+
+ b.Property("SecurityLevel")
+ .HasColumnType("int");
+
+ b.Property("StartupTimeout")
+ .HasColumnType("bigint");
+
+ b.Property("TopicRequestTimeout")
+ .HasColumnType("bigint");
+
+ b.HasKey("Id");
+
+ b.HasIndex("InstanceId")
+ .IsUnique();
+
+ b.ToTable("DreamDaemonSettings");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.DreamMakerSettings", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("ApiValidationPort")
+ .HasColumnType("int");
+
+ b.Property("ApiValidationSecurityLevel")
+ .HasColumnType("int");
+
+ b.Property("InstanceId")
+ .HasColumnType("bigint");
+
+ b.Property("ProjectName")
+ .HasColumnType("nvarchar(max)")
+ .HasMaxLength(10000);
+
+ b.HasKey("Id");
+
+ b.HasIndex("InstanceId")
+ .IsUnique();
+
+ b.ToTable("DreamMakerSettings");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.DualReattachInformation", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("AlphaId")
+ .HasColumnType("bigint");
+
+ b.Property("AlphaIsActive")
+ .HasColumnType("bit");
+
+ b.Property("BravoId")
+ .HasColumnType("bigint");
+
+ b.Property("InstanceId")
+ .HasColumnType("bigint");
+
+ b.HasKey("Id");
+
+ b.HasIndex("AlphaId");
+
+ b.HasIndex("BravoId");
+
+ b.HasIndex("InstanceId")
+ .IsUnique();
+
+ b.ToTable("WatchdogReattachInformations");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.Instance", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("AutoUpdateInterval")
+ .HasColumnType("bigint");
+
+ b.Property("ChatBotLimit")
+ .HasColumnType("int");
+
+ b.Property("ConfigurationType")
+ .HasColumnType("int");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)")
+ .HasMaxLength(10000);
+
+ b.Property("Online")
+ .IsRequired()
+ .HasColumnType("bit");
+
+ b.Property("Path")
+ .IsRequired()
+ .HasColumnType("nvarchar(450)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Path")
+ .IsUnique();
+
+ b.ToTable("Instances");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.InstanceUser", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("ByondRights")
+ .HasColumnType("decimal(20,0)");
+
+ b.Property("ChatBotRights")
+ .HasColumnType("decimal(20,0)");
+
+ b.Property("ConfigurationRights")
+ .HasColumnType("decimal(20,0)");
+
+ b.Property("DreamDaemonRights")
+ .HasColumnType("decimal(20,0)");
+
+ b.Property("DreamMakerRights")
+ .HasColumnType("decimal(20,0)");
+
+ b.Property("InstanceId")
+ .HasColumnType("bigint");
+
+ b.Property("InstanceUserRights")
+ .HasColumnType("decimal(20,0)");
+
+ b.Property("RepositoryRights")
+ .HasColumnType("decimal(20,0)");
+
+ b.Property("UserId")
+ .IsRequired()
+ .HasColumnType("bigint");
+
+ b.HasKey("Id");
+
+ b.HasIndex("InstanceId");
+
+ b.HasIndex("UserId", "InstanceId")
+ .IsUnique();
+
+ b.ToTable("InstanceUsers");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.Job", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("CancelRight")
+ .HasColumnType("decimal(20,0)");
+
+ b.Property("CancelRightsType")
+ .HasColumnType("decimal(20,0)");
+
+ b.Property("Cancelled")
+ .IsRequired()
+ .HasColumnType("bit");
+
+ b.Property("CancelledById")
+ .HasColumnType("bigint");
+
+ b.Property("Description")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("ErrorCode")
+ .HasColumnType("bigint");
+
+ b.Property("ExceptionDetails")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("InstanceId")
+ .HasColumnType("bigint");
+
+ b.Property("StartedAt")
+ .IsRequired()
+ .HasColumnType("datetimeoffset");
+
+ b.Property("StartedById")
+ .HasColumnType("bigint");
+
+ b.Property("StoppedAt")
+ .HasColumnType("datetimeoffset");
+
+ b.HasKey("Id");
+
+ b.HasIndex("CancelledById");
+
+ b.HasIndex("InstanceId");
+
+ b.HasIndex("StartedById");
+
+ b.ToTable("Jobs");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("AccessIdentifier")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("CompileJobId")
+ .HasColumnType("bigint");
+
+ b.Property("IsPrimary")
+ .HasColumnType("bit");
+
+ b.Property("LaunchSecurityLevel")
+ .HasColumnType("int");
+
+ b.Property("Port")
+ .HasColumnType("int");
+
+ b.Property("ProcessId")
+ .HasColumnType("int");
+
+ b.Property("RebootState")
+ .HasColumnType("int");
+
+ b.HasKey("Id");
+
+ b.HasIndex("CompileJobId");
+
+ b.ToTable("ReattachInformations");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.RepositorySettings", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("AccessToken")
+ .HasColumnType("nvarchar(max)")
+ .HasMaxLength(10000);
+
+ b.Property("AccessUser")
+ .HasColumnType("nvarchar(max)")
+ .HasMaxLength(10000);
+
+ b.Property("AutoUpdatesKeepTestMerges")
+ .IsRequired()
+ .HasColumnType("bit");
+
+ b.Property("AutoUpdatesSynchronize")
+ .IsRequired()
+ .HasColumnType("bit");
+
+ b.Property("CommitterEmail")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)")
+ .HasMaxLength(10000);
+
+ b.Property("CommitterName")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)")
+ .HasMaxLength(10000);
+
+ b.Property("InstanceId")
+ .HasColumnType("bigint");
+
+ b.Property("PostTestMergeComment")
+ .IsRequired()
+ .HasColumnType("bit");
+
+ b.Property("PushTestMergeCommits")
+ .IsRequired()
+ .HasColumnType("bit");
+
+ b.Property("ShowTestMergeCommitters")
+ .IsRequired()
+ .HasColumnType("bit");
+
+ b.HasKey("Id");
+
+ b.HasIndex("InstanceId")
+ .IsUnique();
+
+ b.ToTable("RepositorySettings");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.RevInfoTestMerge", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("RevisionInformationId")
+ .HasColumnType("bigint");
+
+ b.Property("TestMergeId")
+ .HasColumnType("bigint");
+
+ b.HasKey("Id");
+
+ b.HasIndex("RevisionInformationId");
+
+ b.HasIndex("TestMergeId");
+
+ b.ToTable("RevInfoTestMerges");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("CommitSha")
+ .IsRequired()
+ .HasColumnType("nvarchar(40)")
+ .HasMaxLength(40);
+
+ b.Property("InstanceId")
+ .HasColumnType("bigint");
+
+ b.Property("OriginCommitSha")
+ .IsRequired()
+ .HasColumnType("nvarchar(40)")
+ .HasMaxLength(40);
+
+ b.HasKey("Id");
+
+ b.HasIndex("InstanceId", "CommitSha")
+ .IsUnique();
+
+ b.ToTable("RevisionInformations");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.TestMerge", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("Author")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("BodyAtMerge")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("Comment")
+ .HasColumnType("nvarchar(max)")
+ .HasMaxLength(10000);
+
+ b.Property("MergedAt")
+ .HasColumnType("datetimeoffset");
+
+ b.Property("MergedById")
+ .HasColumnType("bigint");
+
+ b.Property("Number")
+ .HasColumnType("int");
+
+ b.Property("PrimaryRevisionInformationId")
+ .IsRequired()
+ .HasColumnType("bigint");
+
+ b.Property("PullRequestRevision")
+ .IsRequired()
+ .HasColumnType("nvarchar(40)")
+ .HasMaxLength(40);
+
+ b.Property("TitleAtMerge")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("Url")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("MergedById");
+
+ b.HasIndex("PrimaryRevisionInformationId")
+ .IsUnique();
+
+ b.ToTable("TestMerges");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.User", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("AdministrationRights")
+ .HasColumnType("decimal(20,0)");
+
+ b.Property("CanonicalName")
+ .IsRequired()
+ .HasColumnType("nvarchar(450)");
+
+ b.Property("CreatedAt")
+ .IsRequired()
+ .HasColumnType("datetimeoffset");
+
+ b.Property("CreatedById")
+ .HasColumnType("bigint");
+
+ b.Property("Enabled")
+ .IsRequired()
+ .HasColumnType("bit");
+
+ b.Property("InstanceManagerRights")
+ .HasColumnType("decimal(20,0)");
+
+ b.Property("LastPasswordUpdate")
+ .HasColumnType("datetimeoffset");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)")
+ .HasMaxLength(10000);
+
+ b.Property("PasswordHash")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("SystemIdentifier")
+ .HasColumnType("nvarchar(450)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("CanonicalName")
+ .IsUnique();
+
+ b.HasIndex("CreatedById");
+
+ b.HasIndex("SystemIdentifier")
+ .IsUnique()
+ .HasFilter("[SystemIdentifier] IS NOT NULL");
+
+ b.ToTable("Users");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b =>
+ {
+ b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance")
+ .WithMany("ChatSettings")
+ .HasForeignKey("InstanceId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.ChatChannel", b =>
+ {
+ b.HasOne("Tgstation.Server.Host.Models.ChatBot", "ChatSettings")
+ .WithMany("Channels")
+ .HasForeignKey("ChatSettingsId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.CompileJob", b =>
+ {
+ b.HasOne("Tgstation.Server.Host.Models.Job", "Job")
+ .WithOne()
+ .HasForeignKey("Tgstation.Server.Host.Models.CompileJob", "JobId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Tgstation.Server.Host.Models.RevisionInformation", "RevisionInformation")
+ .WithMany("CompileJobs")
+ .HasForeignKey("RevisionInformationId")
+ .OnDelete(DeleteBehavior.ClientNoAction)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.DreamDaemonSettings", b =>
+ {
+ b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance")
+ .WithOne("DreamDaemonSettings")
+ .HasForeignKey("Tgstation.Server.Host.Models.DreamDaemonSettings", "InstanceId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.DreamMakerSettings", b =>
+ {
+ b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance")
+ .WithOne("DreamMakerSettings")
+ .HasForeignKey("Tgstation.Server.Host.Models.DreamMakerSettings", "InstanceId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.DualReattachInformation", b =>
+ {
+ b.HasOne("Tgstation.Server.Host.Models.ReattachInformation", "Alpha")
+ .WithMany()
+ .HasForeignKey("AlphaId");
+
+ b.HasOne("Tgstation.Server.Host.Models.ReattachInformation", "Bravo")
+ .WithMany()
+ .HasForeignKey("BravoId");
+
+ b.HasOne("Tgstation.Server.Host.Models.Instance", null)
+ .WithOne("WatchdogReattachInformation")
+ .HasForeignKey("Tgstation.Server.Host.Models.DualReattachInformation", "InstanceId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.InstanceUser", b =>
+ {
+ b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance")
+ .WithMany("InstanceUsers")
+ .HasForeignKey("InstanceId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Tgstation.Server.Host.Models.User", null)
+ .WithMany("InstanceUsers")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.Job", b =>
+ {
+ b.HasOne("Tgstation.Server.Host.Models.User", "CancelledBy")
+ .WithMany()
+ .HasForeignKey("CancelledById");
+
+ b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance")
+ .WithMany("Jobs")
+ .HasForeignKey("InstanceId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Tgstation.Server.Host.Models.User", "StartedBy")
+ .WithMany()
+ .HasForeignKey("StartedById")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b =>
+ {
+ b.HasOne("Tgstation.Server.Host.Models.CompileJob", "CompileJob")
+ .WithMany()
+ .HasForeignKey("CompileJobId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.RepositorySettings", b =>
+ {
+ b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance")
+ .WithOne("RepositorySettings")
+ .HasForeignKey("Tgstation.Server.Host.Models.RepositorySettings", "InstanceId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.RevInfoTestMerge", b =>
+ {
+ b.HasOne("Tgstation.Server.Host.Models.RevisionInformation", "RevisionInformation")
+ .WithMany("ActiveTestMerges")
+ .HasForeignKey("RevisionInformationId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Tgstation.Server.Host.Models.TestMerge", "TestMerge")
+ .WithMany("RevisonInformations")
+ .HasForeignKey("TestMergeId")
+ .OnDelete(DeleteBehavior.ClientNoAction)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b =>
+ {
+ b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance")
+ .WithMany("RevisionInformations")
+ .HasForeignKey("InstanceId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.TestMerge", b =>
+ {
+ b.HasOne("Tgstation.Server.Host.Models.User", "MergedBy")
+ .WithMany("TestMerges")
+ .HasForeignKey("MergedById")
+ .OnDelete(DeleteBehavior.Restrict)
+ .IsRequired();
+
+ b.HasOne("Tgstation.Server.Host.Models.RevisionInformation", "PrimaryRevisionInformation")
+ .WithOne("PrimaryTestMerge")
+ .HasForeignKey("Tgstation.Server.Host.Models.TestMerge", "PrimaryRevisionInformationId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.User", b =>
+ {
+ b.HasOne("Tgstation.Server.Host.Models.User", "CreatedBy")
+ .WithMany("CreatedUsers")
+ .HasForeignKey("CreatedById");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/src/Tgstation.Server.Host/Database/Migrations/20200616175424_MSTopicTimeout.cs b/src/Tgstation.Server.Host/Database/Migrations/20200616175424_MSTopicTimeout.cs
new file mode 100644
index 0000000000..fd28951592
--- /dev/null
+++ b/src/Tgstation.Server.Host/Database/Migrations/20200616175424_MSTopicTimeout.cs
@@ -0,0 +1,33 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+using System;
+
+namespace Tgstation.Server.Host.Database.Migrations
+{
+ ///
+ /// Add BYOND topic timeouts for MSSQL.
+ ///
+ public partial class MSTopicTimeout : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ if (migrationBuilder == null)
+ throw new ArgumentNullException(nameof(migrationBuilder));
+ migrationBuilder.AddColumn(
+ name: "TopicRequestTimeout",
+ table: "DreamDaemonSettings",
+ nullable: false,
+ defaultValue: 0L);
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ if (migrationBuilder == null)
+ throw new ArgumentNullException(nameof(migrationBuilder));
+ migrationBuilder.DropColumn(
+ name: "TopicRequestTimeout",
+ table: "DreamDaemonSettings");
+ }
+ }
+}
diff --git a/src/Tgstation.Server.Host/Database/Migrations/20200616175535_MYTopicTimeout.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20200616175535_MYTopicTimeout.Designer.cs
new file mode 100644
index 0000000000..a354fff111
--- /dev/null
+++ b/src/Tgstation.Server.Host/Database/Migrations/20200616175535_MYTopicTimeout.Designer.cs
@@ -0,0 +1,812 @@
+//
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace Tgstation.Server.Host.Database.Migrations
+{
+ [DbContext(typeof(MySqlDatabaseContext))]
+ [Migration("20200616175535_MYTopicTimeout")]
+ partial class MYTopicTimeout
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "3.1.4")
+ .HasAnnotation("Relational:MaxIdentifierLength", 64);
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ b.Property("ChannelLimit")
+ .IsRequired()
+ .HasColumnType("smallint unsigned");
+
+ b.Property("ConnectionString")
+ .IsRequired()
+ .HasColumnType("longtext CHARACTER SET utf8mb4")
+ .HasMaxLength(10000);
+
+ b.Property("Enabled")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("InstanceId")
+ .HasColumnType("bigint");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("varchar(100) CHARACTER SET utf8mb4")
+ .HasMaxLength(100);
+
+ b.Property("Provider")
+ .HasColumnType("int");
+
+ b.Property("ReconnectionInterval")
+ .IsRequired()
+ .HasColumnType("int unsigned");
+
+ b.HasKey("Id");
+
+ b.HasIndex("InstanceId", "Name")
+ .IsUnique();
+
+ b.ToTable("ChatBots");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.ChatChannel", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ b.Property("ChatSettingsId")
+ .HasColumnType("bigint");
+
+ b.Property("DiscordChannelId")
+ .HasColumnType("bigint unsigned");
+
+ b.Property("IrcChannel")
+ .HasColumnType("varchar(100) CHARACTER SET utf8mb4")
+ .HasMaxLength(100);
+
+ b.Property("IsAdminChannel")
+ .IsRequired()
+ .HasColumnType("tinyint(1)");
+
+ b.Property("IsUpdatesChannel")
+ .IsRequired()
+ .HasColumnType("tinyint(1)");
+
+ b.Property("IsWatchdogChannel")
+ .IsRequired()
+ .HasColumnType("tinyint(1)");
+
+ b.Property("Tag")
+ .HasColumnType("longtext CHARACTER SET utf8mb4")
+ .HasMaxLength(10000);
+
+ b.HasKey("Id");
+
+ b.HasIndex("ChatSettingsId", "DiscordChannelId")
+ .IsUnique();
+
+ b.HasIndex("ChatSettingsId", "IrcChannel")
+ .IsUnique();
+
+ b.ToTable("ChatChannels");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.CompileJob", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ b.Property("ByondVersion")
+ .IsRequired()
+ .HasColumnType("longtext CHARACTER SET utf8mb4");
+
+ b.Property("DMApiMajorVersion")
+ .HasColumnType("int");
+
+ b.Property("DMApiMinorVersion")
+ .HasColumnType("int");
+
+ b.Property("DMApiPatchVersion")
+ .HasColumnType("int");
+
+ b.Property("DirectoryName")
+ .IsRequired()
+ .HasColumnType("char(36)");
+
+ b.Property("DmeName")
+ .IsRequired()
+ .HasColumnType("longtext CHARACTER SET utf8mb4");
+
+ b.Property("JobId")
+ .HasColumnType("bigint");
+
+ b.Property("MinimumSecurityLevel")
+ .HasColumnType("int");
+
+ b.Property("Output")
+ .IsRequired()
+ .HasColumnType("longtext CHARACTER SET utf8mb4");
+
+ b.Property("RevisionInformationId")
+ .HasColumnType("bigint");
+
+ b.HasKey("Id");
+
+ b.HasIndex("DirectoryName");
+
+ b.HasIndex("JobId")
+ .IsUnique();
+
+ b.HasIndex("RevisionInformationId");
+
+ b.ToTable("CompileJobs");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.DreamDaemonSettings", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ b.Property("AllowWebClient")
+ .IsRequired()
+ .HasColumnType("tinyint(1)");
+
+ b.Property("AutoStart")
+ .IsRequired()
+ .HasColumnType("tinyint(1)");
+
+ b.Property("HeartbeatSeconds")
+ .IsRequired()
+ .HasColumnType("int unsigned");
+
+ b.Property("InstanceId")
+ .HasColumnType("bigint");
+
+ b.Property("PrimaryPort")
+ .IsRequired()
+ .HasColumnType("smallint unsigned");
+
+ b.Property("SecondaryPort")
+ .IsRequired()
+ .HasColumnType("smallint unsigned");
+
+ b.Property("SecurityLevel")
+ .HasColumnType("int");
+
+ b.Property("StartupTimeout")
+ .IsRequired()
+ .HasColumnType("int unsigned");
+
+ b.Property("TopicRequestTimeout")
+ .IsRequired()
+ .HasColumnType("int unsigned");
+
+ b.HasKey("Id");
+
+ b.HasIndex("InstanceId")
+ .IsUnique();
+
+ b.ToTable("DreamDaemonSettings");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.DreamMakerSettings", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ b.Property("ApiValidationPort")
+ .IsRequired()
+ .HasColumnType("smallint unsigned");
+
+ b.Property("ApiValidationSecurityLevel")
+ .HasColumnType("int");
+
+ b.Property("InstanceId")
+ .HasColumnType("bigint");
+
+ b.Property("ProjectName")
+ .HasColumnType("longtext CHARACTER SET utf8mb4")
+ .HasMaxLength(10000);
+
+ b.HasKey("Id");
+
+ b.HasIndex("InstanceId")
+ .IsUnique();
+
+ b.ToTable("DreamMakerSettings");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.DualReattachInformation", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ b.Property("AlphaId")
+ .HasColumnType("bigint");
+
+ b.Property("AlphaIsActive")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("BravoId")
+ .HasColumnType("bigint");
+
+ b.Property("InstanceId")
+ .HasColumnType("bigint");
+
+ b.HasKey("Id");
+
+ b.HasIndex("AlphaId");
+
+ b.HasIndex("BravoId");
+
+ b.HasIndex("InstanceId")
+ .IsUnique();
+
+ b.ToTable("WatchdogReattachInformations");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.Instance", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ b.Property("AutoUpdateInterval")
+ .IsRequired()
+ .HasColumnType("int unsigned");
+
+ b.Property("ChatBotLimit")
+ .IsRequired()
+ .HasColumnType("smallint unsigned");
+
+ b.Property("ConfigurationType")
+ .HasColumnType("int");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("longtext CHARACTER SET utf8mb4")
+ .HasMaxLength(10000);
+
+ b.Property("Online")
+ .IsRequired()
+ .HasColumnType("tinyint(1)");
+
+ b.Property("Path")
+ .IsRequired()
+ .HasColumnType("varchar(255) CHARACTER SET utf8mb4");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Path")
+ .IsUnique();
+
+ b.ToTable("Instances");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.InstanceUser", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ b.Property("ByondRights")
+ .HasColumnType("bigint unsigned");
+
+ b.Property("ChatBotRights")
+ .HasColumnType("bigint unsigned");
+
+ b.Property("ConfigurationRights")
+ .HasColumnType("bigint unsigned");
+
+ b.Property("DreamDaemonRights")
+ .HasColumnType("bigint unsigned");
+
+ b.Property("DreamMakerRights")
+ .HasColumnType("bigint unsigned");
+
+ b.Property("InstanceId")
+ .HasColumnType("bigint");
+
+ b.Property("InstanceUserRights")
+ .HasColumnType("bigint unsigned");
+
+ b.Property("RepositoryRights")
+ .HasColumnType("bigint unsigned");
+
+ b.Property("UserId")
+ .IsRequired()
+ .HasColumnType("bigint");
+
+ b.HasKey("Id");
+
+ b.HasIndex("InstanceId");
+
+ b.HasIndex("UserId", "InstanceId")
+ .IsUnique();
+
+ b.ToTable("InstanceUsers");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.Job", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ b.Property("CancelRight")
+ .HasColumnType("bigint unsigned");
+
+ b.Property("CancelRightsType")
+ .HasColumnType("bigint unsigned");
+
+ b.Property("Cancelled")
+ .IsRequired()
+ .HasColumnType("tinyint(1)");
+
+ b.Property("CancelledById")
+ .HasColumnType("bigint");
+
+ b.Property("Description")
+ .IsRequired()
+ .HasColumnType("longtext CHARACTER SET utf8mb4");
+
+ b.Property("ErrorCode")
+ .HasColumnType("int unsigned");
+
+ b.Property("ExceptionDetails")
+ .HasColumnType("longtext CHARACTER SET utf8mb4");
+
+ b.Property("InstanceId")
+ .HasColumnType("bigint");
+
+ b.Property("StartedAt")
+ .IsRequired()
+ .HasColumnType("datetime(6)");
+
+ b.Property("StartedById")
+ .HasColumnType("bigint");
+
+ b.Property("StoppedAt")
+ .HasColumnType("datetime(6)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("CancelledById");
+
+ b.HasIndex("InstanceId");
+
+ b.HasIndex("StartedById");
+
+ b.ToTable("Jobs");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ b.Property("AccessIdentifier")
+ .IsRequired()
+ .HasColumnType("longtext CHARACTER SET utf8mb4");
+
+ b.Property("CompileJobId")
+ .HasColumnType("bigint");
+
+ b.Property("IsPrimary")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("LaunchSecurityLevel")
+ .HasColumnType("int");
+
+ b.Property("Port")
+ .HasColumnType("smallint unsigned");
+
+ b.Property("ProcessId")
+ .HasColumnType("int");
+
+ b.Property("RebootState")
+ .HasColumnType("int");
+
+ b.HasKey("Id");
+
+ b.HasIndex("CompileJobId");
+
+ b.ToTable("ReattachInformations");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.RepositorySettings", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ b.Property("AccessToken")
+ .HasColumnType("longtext CHARACTER SET utf8mb4")
+ .HasMaxLength(10000);
+
+ b.Property("AccessUser")
+ .HasColumnType("longtext CHARACTER SET utf8mb4")
+ .HasMaxLength(10000);
+
+ b.Property("AutoUpdatesKeepTestMerges")
+ .IsRequired()
+ .HasColumnType("tinyint(1)");
+
+ b.Property("AutoUpdatesSynchronize")
+ .IsRequired()
+ .HasColumnType("tinyint(1)");
+
+ b.Property("CommitterEmail")
+ .IsRequired()
+ .HasColumnType("longtext CHARACTER SET utf8mb4")
+ .HasMaxLength(10000);
+
+ b.Property("CommitterName")
+ .IsRequired()
+ .HasColumnType("longtext CHARACTER SET utf8mb4")
+ .HasMaxLength(10000);
+
+ b.Property("InstanceId")
+ .HasColumnType("bigint");
+
+ b.Property("PostTestMergeComment")
+ .IsRequired()
+ .HasColumnType("tinyint(1)");
+
+ b.Property("PushTestMergeCommits")
+ .IsRequired()
+ .HasColumnType("tinyint(1)");
+
+ b.Property("ShowTestMergeCommitters")
+ .IsRequired()
+ .HasColumnType("tinyint(1)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("InstanceId")
+ .IsUnique();
+
+ b.ToTable("RepositorySettings");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.RevInfoTestMerge", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ b.Property("RevisionInformationId")
+ .HasColumnType("bigint");
+
+ b.Property("TestMergeId")
+ .HasColumnType("bigint");
+
+ b.HasKey("Id");
+
+ b.HasIndex("RevisionInformationId");
+
+ b.HasIndex("TestMergeId");
+
+ b.ToTable("RevInfoTestMerges");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ b.Property("CommitSha")
+ .IsRequired()
+ .HasColumnType("varchar(40) CHARACTER SET utf8mb4")
+ .HasMaxLength(40);
+
+ b.Property("InstanceId")
+ .HasColumnType("bigint");
+
+ b.Property("OriginCommitSha")
+ .IsRequired()
+ .HasColumnType("varchar(40) CHARACTER SET utf8mb4")
+ .HasMaxLength(40);
+
+ b.HasKey("Id");
+
+ b.HasIndex("InstanceId", "CommitSha")
+ .IsUnique();
+
+ b.ToTable("RevisionInformations");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.TestMerge", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ b.Property