diff --git a/src/Tgstation.Server.Host.Console/Tgstation.Server.Host.Console.csproj b/src/Tgstation.Server.Host.Console/Tgstation.Server.Host.Console.csproj
index bb659a9233..d181d5f605 100644
--- a/src/Tgstation.Server.Host.Console/Tgstation.Server.Host.Console.csproj
+++ b/src/Tgstation.Server.Host.Console/Tgstation.Server.Host.Console.csproj
@@ -4,7 +4,7 @@
Exe
netcoreapp2.1
Full
- 4.0.1.3
+ 4.0.1.4
diff --git a/src/Tgstation.Server.Host.Service/Properties/AssemblyInfo.cs b/src/Tgstation.Server.Host.Service/Properties/AssemblyInfo.cs
index 88bf8ee48f..2b77d018db 100644
--- a/src/Tgstation.Server.Host.Service/Properties/AssemblyInfo.cs
+++ b/src/Tgstation.Server.Host.Service/Properties/AssemblyInfo.cs
@@ -7,5 +7,5 @@ using System.Runtime.InteropServices;
[assembly: Guid("29927416-3b78-49a7-a560-5ccaa638b6b4")]
[assembly: InternalsVisibleTo("Tgstation.Server.Host.Service.Tests")]
-[assembly: AssemblyVersion("4.0.1.3")]
-[assembly: AssemblyFileVersion("4.0.1.3")]
+[assembly: AssemblyVersion("4.0.1.4")]
+[assembly: AssemblyFileVersion("4.0.1.4")]
diff --git a/src/Tgstation.Server.Host.Watchdog/Tgstation.Server.Host.Watchdog.csproj b/src/Tgstation.Server.Host.Watchdog/Tgstation.Server.Host.Watchdog.csproj
index 2d3d915541..ec75cc5b0d 100644
--- a/src/Tgstation.Server.Host.Watchdog/Tgstation.Server.Host.Watchdog.csproj
+++ b/src/Tgstation.Server.Host.Watchdog/Tgstation.Server.Host.Watchdog.csproj
@@ -4,7 +4,7 @@
netstandard2.0
Full
false
- 4.0.1.3
+ 4.0.1.4
diff --git a/src/Tgstation.Server.Host/Components/Chat/Channel.cs b/src/Tgstation.Server.Host/Components/Chat/Channel.cs
index 131ce67962..fe5d6acb15 100644
--- a/src/Tgstation.Server.Host/Components/Chat/Channel.cs
+++ b/src/Tgstation.Server.Host/Components/Chat/Channel.cs
@@ -38,12 +38,12 @@ namespace Tgstation.Server.Host.Components.Chat
///
/// If this is considered a channel for admin commands
///
- public bool IsAdmin { get; set; }
+ public bool IsAdminChannel { get; set; }
///
/// If this is a 1-to-1 chat channel
///
- public bool IsPrivate { get; set; }
+ public bool IsPrivateChannel { get; set; }
///
/// For user use
diff --git a/src/Tgstation.Server.Host/Components/Chat/Chat.cs b/src/Tgstation.Server.Host/Components/Chat/Chat.cs
index b4d68b1139..fc7321af84 100644
--- a/src/Tgstation.Server.Host/Components/Chat/Chat.cs
+++ b/src/Tgstation.Server.Host/Components/Chat/Chat.cs
@@ -195,7 +195,7 @@ namespace Tgstation.Server.Host.Components.Chat
{
var providerId = providers.Where(x => x.Value == provider).Select(x => x.Key).First();
var enumerable = mappedChannels.Where(x => x.Value.ProviderId == providerId && x.Value.ProviderChannelId == message.User.Channel.RealId);
- if (message.User.Channel.IsPrivate)
+ if (message.User.Channel.IsPrivateChannel)
lock (mappedChannels)
{
if (!provider.Connected)
@@ -223,7 +223,7 @@ namespace Tgstation.Server.Host.Components.Chat
var mapping = enumerable.First().Value;
message.User.Channel.Id = mapping.Channel.Id;
message.User.Channel.Tag = mapping.Channel.Tag;
- message.User.Channel.IsAdmin = mapping.Channel.IsAdmin;
+ message.User.Channel.IsAdminChannel = mapping.Channel.IsAdminChannel;
}
}
@@ -236,7 +236,7 @@ namespace Tgstation.Server.Host.Components.Chat
var addressed = address == CommonMention.ToUpperInvariant() || address == provider.BotMention.ToUpperInvariant();
- if (!addressed && !message.User.Channel.IsPrivate)
+ if (!addressed && !message.User.Channel.IsPrivateChannel)
//no mention
return;
@@ -302,7 +302,7 @@ namespace Tgstation.Server.Host.Components.Chat
return;
}
- if (commandHandler.AdminOnly && !message.User.Channel.IsAdmin)
+ if (commandHandler.AdminOnly && !message.User.Channel.IsAdminChannel)
{
await SendMessage("Use this command in an admin channel!", new List { message.User.Channel.RealId }, cancellationToken).ConfigureAwait(false);
return;
diff --git a/src/Tgstation.Server.Host/Components/Chat/Commands/ICommand.cs b/src/Tgstation.Server.Host/Components/Chat/Commands/ICommand.cs
index 8694606731..4ff8799ce7 100644
--- a/src/Tgstation.Server.Host/Components/Chat/Commands/ICommand.cs
+++ b/src/Tgstation.Server.Host/Components/Chat/Commands/ICommand.cs
@@ -19,7 +19,7 @@ namespace Tgstation.Server.Host.Components.Chat.Commands
string HelpText { get; }
///
- /// If the command should only be available to s who's has set
+ /// If the command should only be available to s who's has set
///
bool AdminOnly { get; }
diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs
index 711454887c..50996ed74a 100644
--- a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs
+++ b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs
@@ -97,7 +97,7 @@ namespace Tgstation.Server.Host.Components.Chat.Providers
Channel = new Channel
{
RealId = e.Channel.Id,
- IsPrivate = pm,
+ IsPrivateChannel = pm,
ConnectionName = pm ? e.Author.Username : (e.Channel as ITextChannel)?.Guild.Name ?? "UNKNOWN",
FriendlyName = e.Channel.Name
//isAdmin and Tag populated by manager
@@ -188,10 +188,10 @@ namespace Tgstation.Server.Host.Components.Chat.Providers
return new Channel
{
RealId = discordChannel.Id,
- IsAdmin = channel.IsAdminChannel == true,
+ IsAdminChannel = channel.IsAdminChannel == true,
ConnectionName = discordChannel.Guild.Name,
FriendlyName = discordChannel.Name,
- IsPrivate = false,
+ IsPrivateChannel = false,
Tag = channel.Tag
};
};
diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs
index cd08c1760e..01fa89697e 100644
--- a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs
+++ b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs
@@ -204,7 +204,7 @@ namespace Tgstation.Server.Host.Components.Chat.Providers
ConnectionName = address,
FriendlyName = isPrivate ? String.Format(CultureInfo.InvariantCulture, "PM: {0}", channelName) : channelName,
RealId = channelId,
- IsPrivate = isPrivate
+ IsPrivateChannel = isPrivate
//isAdmin and Tag populated by manager
},
FriendlyName = username,
@@ -393,10 +393,10 @@ namespace Tgstation.Server.Host.Components.Chat.Providers
return new Channel
{
RealId = id.Value,
- IsAdmin = x.IsAdminChannel == true,
+ IsAdminChannel = x.IsAdminChannel == true,
ConnectionName = address,
FriendlyName = channelIdMap[id.Value],
- IsPrivate = false,
+ IsPrivateChannel = false,
Tag = x.Tag
};
}).ToList();
diff --git a/src/Tgstation.Server.Host/Components/InstanceManager.cs b/src/Tgstation.Server.Host/Components/InstanceManager.cs
index 88a2286d47..b9b558cba2 100644
--- a/src/Tgstation.Server.Host/Components/InstanceManager.cs
+++ b/src/Tgstation.Server.Host/Components/InstanceManager.cs
@@ -12,7 +12,7 @@ using Tgstation.Server.Host.IO;
namespace Tgstation.Server.Host.Components
{
///
- sealed class InstanceManager : IInstanceManager, IHostedService, IDisposable
+ sealed class InstanceManager : IInstanceManager, IRestartHandler, IHostedService, IDisposable
{
///
/// The for the
@@ -49,6 +49,11 @@ namespace Tgstation.Server.Host.Components
///
readonly Dictionary instances;
+ ///
+ /// Used in to determine if database downgrades must be made
+ ///
+ Version downgradeVersion;
+
///
/// If the has been d
///
@@ -62,16 +67,21 @@ namespace Tgstation.Server.Host.Components
/// The value of
/// The value of
/// The value of
+ /// The used to register the as a
/// The value of
- public InstanceManager(IInstanceFactory instanceFactory, IIOManager ioManager, IDatabaseContextFactory databaseContextFactory, IApplication application, IJobManager jobManager, ILogger logger)
+ public InstanceManager(IInstanceFactory instanceFactory, IIOManager ioManager, IDatabaseContextFactory databaseContextFactory, IApplication application, IJobManager jobManager, IServerControl serverControl, ILogger logger)
{
this.instanceFactory = instanceFactory ?? throw new ArgumentNullException(nameof(instanceFactory));
this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager));
this.databaseContextFactory = databaseContextFactory ?? throw new ArgumentNullException(nameof(databaseContextFactory));
this.application = application ?? throw new ArgumentNullException(nameof(application));
this.jobManager = jobManager ?? throw new ArgumentNullException(nameof(jobManager));
+ if (serverControl == null)
+ throw new ArgumentNullException(nameof(serverControl));
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
+ serverControl.RegisterForRestart(this);
+
instances = new Dictionary();
}
@@ -225,6 +235,17 @@ namespace Tgstation.Server.Host.Components
await jobManager.StopAsync(cancellationToken).ConfigureAwait(false);
await Task.WhenAll(instances.Select(x => x.Value.StopAsync(cancellationToken))).ConfigureAwait(false);
await instanceFactory.StopAsync(cancellationToken).ConfigureAwait(false);
+
+ //downgrade the db if necessary
+ if (downgradeVersion != null)
+ await databaseContextFactory.UseContext(db => db.SchemaDowngradeForServerVersion(downgradeVersion, cancellationToken)).ConfigureAwait(false);
+ }
+
+ ///
+ public Task HandleRestart(Version updateVersion, CancellationToken cancellationToken)
+ {
+ downgradeVersion = updateVersion != null && updateVersion < application.Version ? updateVersion : null;
+ return Task.CompletedTask;
}
}
}
diff --git a/src/Tgstation.Server.Host/Components/Interop/ChatCommand.cs b/src/Tgstation.Server.Host/Components/Interop/ChatCommand.cs
index 1c49476b35..a8cc05feba 100644
--- a/src/Tgstation.Server.Host/Components/Interop/ChatCommand.cs
+++ b/src/Tgstation.Server.Host/Components/Interop/ChatCommand.cs
@@ -5,7 +5,7 @@ namespace Tgstation.Server.Host.Components.Interop
sealed class ChatCommand
{
public string Command { get; set; }
- public string Parameters { get; set; }
+ public string Params { get; set; }
public User User { get; set; }
}
}
diff --git a/src/Tgstation.Server.Host/Components/Interop/CommCommand.cs b/src/Tgstation.Server.Host/Components/Interop/CommCommand.cs
index 7145d35aae..31b4715897 100644
--- a/src/Tgstation.Server.Host/Components/Interop/CommCommand.cs
+++ b/src/Tgstation.Server.Host/Components/Interop/CommCommand.cs
@@ -10,7 +10,7 @@ namespace Tgstation.Server.Host.Components.Interop
///
/// The dictionary of the
///
- public IReadOnlyDictionary Parameters { get; set; }
+ public IReadOnlyDictionary Parameters { get; set; }
///
/// The raw JSON of the
diff --git a/src/Tgstation.Server.Host/Components/Interop/CommContext.cs b/src/Tgstation.Server.Host/Components/Interop/CommContext.cs
index f9c5208d88..e910ad7ffa 100644
--- a/src/Tgstation.Server.Host/Components/Interop/CommContext.cs
+++ b/src/Tgstation.Server.Host/Components/Interop/CommContext.cs
@@ -109,7 +109,7 @@ namespace Tgstation.Server.Host.Components.Interop
{
command = new CommCommand
{
- Parameters = JsonConvert.DeserializeObject>(file),
+ Parameters = JsonConvert.DeserializeObject>(file),
RawJson = file
};
}
diff --git a/src/Tgstation.Server.Host/Components/Watchdog/SessionController.cs b/src/Tgstation.Server.Host/Components/Watchdog/SessionController.cs
index 8cd90b5b72..d8fa568f03 100644
--- a/src/Tgstation.Server.Host/Components/Watchdog/SessionController.cs
+++ b/src/Tgstation.Server.Host/Components/Watchdog/SessionController.cs
@@ -221,6 +221,8 @@ namespace Tgstation.Server.Host.Components.Watchdog
return result;
};
LaunchResult = GetLaunchResult();
+
+ logger.LogDebug("Created session controller. Primary: {0}, CommsKey: {1}, Port: {2}", IsPrimary, reattachInformation.AccessIdentifier, Port);
}
///
@@ -316,7 +318,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
case Constants.DMCommandNewPort:
lock (this)
{
- if (!query.TryGetValue(Constants.DMParameterData, out var stringPort) || !UInt16.TryParse(stringPort, out var currentPort))
+ if (!query.TryGetValue(Constants.DMParameterData, out var stringPortObject) || !UInt16.TryParse(stringPortObject as string, out var currentPort))
{
/////UHHHH
logger.LogWarning("DreamDaemon sent new port command without providing it's own!");
@@ -354,7 +356,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
content = new ErrorMessage { Message = "Invalid API validation request!" };
break;
}
- if (!query.TryGetValue(Constants.DMParameterData, out var stringMinimumSecurityLevel) || !Enum.TryParse(stringMinimumSecurityLevel, out var minimumSecurityLevel))
+ if (!query.TryGetValue(Constants.DMParameterData, out var stringMinimumSecurityLevelObject) || !Enum.TryParse(stringMinimumSecurityLevelObject as string, out var minimumSecurityLevel))
apiValidationStatus = ApiValidationStatus.BadValidationRequest;
else
switch (minimumSecurityLevel)
@@ -479,6 +481,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
return false;
}
+ reattachInformation.Port = port;
return true;
}
diff --git a/src/Tgstation.Server.Host/Components/Watchdog/Watchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/Watchdog.cs
index 0302b24fce..882a07170e 100644
--- a/src/Tgstation.Server.Host/Components/Watchdog/Watchdog.cs
+++ b/src/Tgstation.Server.Host/Components/Watchdog/Watchdog.cs
@@ -453,20 +453,13 @@ namespace Tgstation.Server.Host.Components.Watchdog
//servers now swapped
- //enable this now
- monitorState.ActiveServer.ClosePortOnReboot = true;
+ //enable this now if inactive server is not still valid
+ monitorState.ActiveServer.ClosePortOnReboot = restartOnceSwapped;
if (!restartOnceSwapped)
- {
- //inactive server still valid
-
- //disable this
- monitorState.InactiveServer.ClosePortOnReboot = false;
-
//now try to reopen it on the private port
//failing that, just reboot it
restartOnceSwapped = !await monitorState.InactiveServer.SetPort(ActiveLaunchParameters.SecondaryPort.Value, cancellationToken).ConfigureAwait(false);
- }
//break either way because any issues past this point would be solved by the reboot
if (restartOnceSwapped)
@@ -1059,7 +1052,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
var commandObject = new ChatCommand
{
Command = commandName,
- Parameters = arguments,
+ Params = arguments,
User = sender
};
diff --git a/src/Tgstation.Server.Host/Models/DatabaseContext.cs b/src/Tgstation.Server.Host/Models/DatabaseContext.cs
index 7578c21c8a..e113f1d999 100644
--- a/src/Tgstation.Server.Host/Models/DatabaseContext.cs
+++ b/src/Tgstation.Server.Host/Models/DatabaseContext.cs
@@ -1,7 +1,11 @@
using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
+using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -169,5 +173,51 @@ namespace Tgstation.Server.Host.Models
///
public Task Save(CancellationToken cancellationToken) => SaveChangesAsync(cancellationToken);
+
+ ///
+ /// If the MY_ class of migrations should be used instead of the MS_ class
+ ///
+ /// if the MY_ class of migrations should be used instead of the MS_ class, otherwise
+ protected abstract bool UseMySQLMigrations();
+
+ ///
+ public async Task SchemaDowngradeForServerVersion(Version version, CancellationToken cancellationToken)
+ {
+ if (version == null)
+ throw new ArgumentNullException(nameof(version));
+ if (version < new Version(4, 0))
+ throw new ArgumentOutOfRangeException(nameof(version), version, "Not a valid V4 version!");
+
+ string targetMigration = null;
+
+ //Update this with new migrations as they are made
+ //Always use the MS class
+
+ //TODO: Uncomment once #816 is merged
+ /*
+ if (version < new Version(4, 0, 2))
+ targetMigration = nameof(MSReattachCompileJobRequired);
+ */
+
+ if (targetMigration == null)
+ return;
+
+ if (UseMySQLMigrations())
+ targetMigration = String.Format(CultureInfo.InvariantCulture, "MY" + targetMigration.Substring(2));
+
+ //even though it clearly implements it in the DatabaseFacade definition this won't work without casting (╯ಠ益ಠ)╯︵ ┻━┻
+ var dbServiceProvider = ((IInfrastructure)Database).Instance;
+ var migrator = dbServiceProvider.GetRequiredService();
+
+ Logger.LogInformation("Migrating down to version {0}. Target: {1}", version, targetMigration);
+ try
+ {
+ await migrator.MigrateAsync(targetMigration, cancellationToken).ConfigureAwait(false);
+ }
+ catch (Exception e)
+ {
+ Logger.LogCritical("Failed to migrate! Exception: {0}", e);
+ }
+ }
}
}
diff --git a/src/Tgstation.Server.Host/Models/IDatabaseContext.cs b/src/Tgstation.Server.Host/Models/IDatabaseContext.cs
index 8fdb8aad74..e7c8e9dcd2 100644
--- a/src/Tgstation.Server.Host/Models/IDatabaseContext.cs
+++ b/src/Tgstation.Server.Host/Models/IDatabaseContext.cs
@@ -1,4 +1,5 @@
using Microsoft.EntityFrameworkCore;
+using System;
using System.Threading;
using System.Threading.Tasks;
@@ -87,5 +88,13 @@ namespace Tgstation.Server.Host.Models
/// The for the operation
/// A representing the running operation
Task Initialize(CancellationToken cancellationToken);
+
+ ///
+ /// Attempt to downgrade the schema to the migration used for a given server
+ ///
+ /// The tgstation-server that the schema should downgrade for
+ /// The for the operation
+ /// A representing the running operation
+ Task SchemaDowngradeForServerVersion(Version version, CancellationToken cancellationToken);
}
}
diff --git a/src/Tgstation.Server.Host/Models/MySqlDatabaseContext.cs b/src/Tgstation.Server.Host/Models/MySqlDatabaseContext.cs
index 8c03b31ee0..718fc04d98 100644
--- a/src/Tgstation.Server.Host/Models/MySqlDatabaseContext.cs
+++ b/src/Tgstation.Server.Host/Models/MySqlDatabaseContext.cs
@@ -38,5 +38,8 @@ namespace Tgstation.Server.Host.Models
else
options.UseMySql(DatabaseConfiguration.ConnectionString);
}
+
+ ///
+ protected override bool UseMySQLMigrations() => true;
}
}
diff --git a/src/Tgstation.Server.Host/Models/SqlServerDatabaseContext.cs b/src/Tgstation.Server.Host/Models/SqlServerDatabaseContext.cs
index d3d5aa8260..94240566d3 100644
--- a/src/Tgstation.Server.Host/Models/SqlServerDatabaseContext.cs
+++ b/src/Tgstation.Server.Host/Models/SqlServerDatabaseContext.cs
@@ -26,5 +26,8 @@ namespace Tgstation.Server.Host.Models
base.OnConfiguring(options);
options.UseSqlServer(DatabaseConfiguration.ConnectionString);
}
+
+ ///
+ protected override bool UseMySQLMigrations() => false;
}
}
diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj
index edb20c1711..a52ca184ad 100644
--- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj
+++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj
@@ -3,7 +3,7 @@
netcoreapp2.1
Full
- 4.0.1.3
+ 4.0.1.4