diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml
index b61a1e318e0..bdb5180462e 100644
--- a/.github/workflows/ci-pipeline.yml
+++ b/.github/workflows/ci-pipeline.yml
@@ -1276,7 +1276,7 @@ jobs:
path: ./code_coverage/integration_tests/windows_integration_tests_release_system_sqlite
- name: Upload Coverage to CodeCov
- uses: codecov/codecov-action@v4
+ uses: codecov/codecov-action@v5
with:
directory: ./code_coverage
fail_ci_if_error: true
@@ -1538,6 +1538,10 @@ jobs:
if (Test-Path -Path $log -PathType Leaf) {
Get-Content $log
}
+ $potentialMsiLog = [System.IO.Path]::GetFullPath("install_000_tgstation_server.msi.log")
+ if (Test-Path -Path $potentialMsiLog -PathType Leaf) {
+ Get-Content $potentialMsiLog
+ }
$installCode = $procMain.ExitCode
if($installCode -ne 0) {
Write-Host "ERROR INSTALLER EXIT CODE $installCode"
diff --git a/build/TestCommon.props b/build/TestCommon.props
index 719e316c8ea..02a6453fe86 100644
--- a/build/TestCommon.props
+++ b/build/TestCommon.props
@@ -18,9 +18,9 @@
-
+
-
+
diff --git a/build/Version.props b/build/Version.props
index 02bbc0e30a4..8209b0f18a0 100644
--- a/build/Version.props
+++ b/build/Version.props
@@ -8,14 +8,13 @@
10.12.0
0.5.0
7.0.0
- 16.3.0
- 19.3.0
+ 17.0.0
+ 20.0.0
7.3.0
5.10.0
1.6.0
8.0.0
1.2.1
- 2.0.0
netstandard2.0
8
diff --git a/build/package/winget/Tgstation.Server.Host.Service.Wix.Bundle/Bundle.wxs b/build/package/winget/Tgstation.Server.Host.Service.Wix.Bundle/Bundle.wxs
index 9caccc81aee..ac3386ff60e 100644
--- a/build/package/winget/Tgstation.Server.Host.Service.Wix.Bundle/Bundle.wxs
+++ b/build/package/winget/Tgstation.Server.Host.Service.Wix.Bundle/Bundle.wxs
@@ -1,7 +1,7 @@
-
+
diff --git a/build/package/winget/Tgstation.Server.Host.Service.Wix.Extensions/InstallationExtensions.cs b/build/package/winget/Tgstation.Server.Host.Service.Wix.Extensions/InstallationExtensions.cs
index d6a46b77006..ddecf51c9a0 100644
--- a/build/package/winget/Tgstation.Server.Host.Service.Wix.Extensions/InstallationExtensions.cs
+++ b/build/package/winget/Tgstation.Server.Host.Service.Wix.Extensions/InstallationExtensions.cs
@@ -16,7 +16,7 @@ public static class InstallationExtensions
///
/// Package name
///
- /// As much as I'd like to use Tgstation.Server.Common.Constants.CanonicalPackageName here, attempting to reference it makes Tgstation.Server.Migrator.Comms fail due to referencing the net2.0 version of that library. EVEN THOUGH IT'S A TRANSITIVE DEPENDENCY OF Tgstation.Server.Client!!!!! If that dead-ass tool has been removed, feel free to do this.
+ /// As much as I'd like to use Tgstation.Server.Common.Constants.CanonicalPackageName here, attempting to reference it makes VS go crazy with fake errors.
const string CanonicalPackageName = "tgstation-server";
///
diff --git a/build/package/winget/Tgstation.Server.Host.Service.Wix/Package.wxs b/build/package/winget/Tgstation.Server.Host.Service.Wix/Package.wxs
index 240250b62f4..bde9181f975 100644
--- a/build/package/winget/Tgstation.Server.Host.Service.Wix/Package.wxs
+++ b/build/package/winget/Tgstation.Server.Host.Service.Wix/Package.wxs
@@ -48,6 +48,10 @@
+
+
+
+
diff --git a/build/package/winget/Tgstation.Server.Host.Service.Wix/Tgstation.Server.Host.Service.Wix.wixproj b/build/package/winget/Tgstation.Server.Host.Service.Wix/Tgstation.Server.Host.Service.Wix.wixproj
index 9ca13531e21..272694a58e5 100644
--- a/build/package/winget/Tgstation.Server.Host.Service.Wix/Tgstation.Server.Host.Service.Wix.wixproj
+++ b/build/package/winget/Tgstation.Server.Host.Service.Wix/Tgstation.Server.Host.Service.Wix.wixproj
@@ -18,11 +18,6 @@
true
true
-
- ServiceHostWatchdogComponentGroup
- ApplicationDirectory
- true
-
diff --git a/src/Tgstation.Server.Api/Tgstation.Server.Api.csproj b/src/Tgstation.Server.Api/Tgstation.Server.Api.csproj
index 73092b2ba6e..a7aafbcc6cf 100644
--- a/src/Tgstation.Server.Api/Tgstation.Server.Api.csproj
+++ b/src/Tgstation.Server.Api/Tgstation.Server.Api.csproj
@@ -28,9 +28,10 @@
-
+
+
diff --git a/src/Tgstation.Server.Client.GraphQL/Tgstation.Server.Client.GraphQL.csproj b/src/Tgstation.Server.Client.GraphQL/Tgstation.Server.Client.GraphQL.csproj
index 780cbbcd7cf..34f1cda13c0 100644
--- a/src/Tgstation.Server.Client.GraphQL/Tgstation.Server.Client.GraphQL.csproj
+++ b/src/Tgstation.Server.Client.GraphQL/Tgstation.Server.Client.GraphQL.csproj
@@ -9,8 +9,8 @@
-
-
+
+
diff --git a/src/Tgstation.Server.Client/Tgstation.Server.Client.csproj b/src/Tgstation.Server.Client/Tgstation.Server.Client.csproj
index 5046c091a88..91278a6dcde 100644
--- a/src/Tgstation.Server.Client/Tgstation.Server.Client.csproj
+++ b/src/Tgstation.Server.Client/Tgstation.Server.Client.csproj
@@ -11,9 +11,9 @@
-
+
-
+
diff --git a/src/Tgstation.Server.Common/Tgstation.Server.Common.csproj b/src/Tgstation.Server.Common/Tgstation.Server.Common.csproj
index b23195dfca9..4b119caf8b1 100644
--- a/src/Tgstation.Server.Common/Tgstation.Server.Common.csproj
+++ b/src/Tgstation.Server.Common/Tgstation.Server.Common.csproj
@@ -12,7 +12,7 @@
-
+
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 9804e251e3f..57b784056e3 100644
--- a/src/Tgstation.Server.Host.Console/Tgstation.Server.Host.Console.csproj
+++ b/src/Tgstation.Server.Host.Console/Tgstation.Server.Host.Console.csproj
@@ -13,9 +13,9 @@
-
+
-
+
diff --git a/src/Tgstation.Server.Host.Service/Program.cs b/src/Tgstation.Server.Host.Service/Program.cs
index 4a9d39fcd21..53623ff2b80 100644
--- a/src/Tgstation.Server.Host.Service/Program.cs
+++ b/src/Tgstation.Server.Host.Service/Program.cs
@@ -190,10 +190,9 @@ void InvokeSC(string? serviceToUninstall)
// Mimicing Tgstation.Server.Host.Service.Wix here, which is the source of truth for this data
installer.Context = new InstallContext(
Path.Combine(programDataDirectory, $"tgs-install-{Guid.NewGuid()}.log"),
- new[]
- {
+ [
$"assemblypath=\"{exePath}\"{(String.IsNullOrWhiteSpace(PassthroughArgs) ? String.Empty : $" -p=\"{PassthroughArgs}\"")}",
- });
+ ]);
installer.Description = $"{Server.Common.Constants.CanonicalPackageName} running as a Windows service.";
installer.DisplayName = Server.Common.Constants.CanonicalPackageName;
installer.StartType = ServiceStartMode.Automatic;
diff --git a/src/Tgstation.Server.Host.Service/Tgstation.Server.Host.Service.csproj b/src/Tgstation.Server.Host.Service/Tgstation.Server.Host.Service.csproj
index e1f04e898b2..80a62d106df 100644
--- a/src/Tgstation.Server.Host.Service/Tgstation.Server.Host.Service.csproj
+++ b/src/Tgstation.Server.Host.Service/Tgstation.Server.Host.Service.csproj
@@ -21,15 +21,21 @@
-
+
-
+
-
+
+
+
+
+
+
+
-
+
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 dad6a144544..7b46bb024a6 100644
--- a/src/Tgstation.Server.Host.Watchdog/Tgstation.Server.Host.Watchdog.csproj
+++ b/src/Tgstation.Server.Host.Watchdog/Tgstation.Server.Host.Watchdog.csproj
@@ -10,7 +10,7 @@
-
+
diff --git a/src/Tgstation.Server.Host/.config/dotnet-tools.json b/src/Tgstation.Server.Host/.config/dotnet-tools.json
index 6b7095305f3..02afa3f0723 100644
--- a/src/Tgstation.Server.Host/.config/dotnet-tools.json
+++ b/src/Tgstation.Server.Host/.config/dotnet-tools.json
@@ -3,7 +3,7 @@
"isRoot": true,
"tools": {
"dotnet-ef": {
- "version": "8.0.10",
+ "version": "8.0.11",
"commands": [
"dotnet-ef"
]
diff --git a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs
index e0aff03f405..7fa4fc4926d 100644
--- a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs
+++ b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs
@@ -1,11 +1,10 @@
using System;
using System.Collections.Generic;
+using System.ComponentModel;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
-using BetterWin32Errors;
-
using Microsoft.Extensions.Logging;
using Serilog.Context;
diff --git a/src/Tgstation.Server.Host/IO/WindowsFilesystemLinkFactory.cs b/src/Tgstation.Server.Host/IO/WindowsFilesystemLinkFactory.cs
index 6636838ab42..54ff36b3205 100644
--- a/src/Tgstation.Server.Host/IO/WindowsFilesystemLinkFactory.cs
+++ b/src/Tgstation.Server.Host/IO/WindowsFilesystemLinkFactory.cs
@@ -1,10 +1,9 @@
using System;
+using System.ComponentModel;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
-using BetterWin32Errors;
-
using Tgstation.Server.Host.System;
namespace Tgstation.Server.Host.IO
diff --git a/src/Tgstation.Server.Host/System/WindowsNetworkPromptReaper.cs b/src/Tgstation.Server.Host/System/WindowsNetworkPromptReaper.cs
index 9bbcd497ce0..bd7b1f645ec 100644
--- a/src/Tgstation.Server.Host/System/WindowsNetworkPromptReaper.cs
+++ b/src/Tgstation.Server.Host/System/WindowsNetworkPromptReaper.cs
@@ -1,13 +1,12 @@
using System;
using System.Collections.Generic;
+using System.ComponentModel;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
-using BetterWin32Errors;
-
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
diff --git a/src/Tgstation.Server.Host/System/WindowsProcessFeatures.cs b/src/Tgstation.Server.Host/System/WindowsProcessFeatures.cs
index 6b71b2b2539..21855c0062e 100644
--- a/src/Tgstation.Server.Host/System/WindowsProcessFeatures.cs
+++ b/src/Tgstation.Server.Host/System/WindowsProcessFeatures.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
@@ -8,7 +9,6 @@
using System.Threading;
using System.Threading.Tasks;
-using BetterWin32Errors;
using Microsoft.Extensions.Logging;
using Tgstation.Server.Api.Models;
diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj
index 570b627d6e0..084b814d7c0 100644
--- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj
+++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj
@@ -87,48 +87,46 @@
-
-
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
-
+
@@ -136,7 +134,7 @@
-
+
@@ -144,7 +142,7 @@
-
+
@@ -152,15 +150,15 @@
-
+
-
+
-
+
-
+
-
+
diff --git a/src/Tgstation.Server.Shared/Tgstation.Server.Shared.csproj b/src/Tgstation.Server.Shared/Tgstation.Server.Shared.csproj
index 14c6e899813..ed81c623411 100644
--- a/src/Tgstation.Server.Shared/Tgstation.Server.Shared.csproj
+++ b/src/Tgstation.Server.Shared/Tgstation.Server.Shared.csproj
@@ -10,11 +10,11 @@
-
+
-
+
diff --git a/tests/Tgstation.Server.Client.Tests/Tgstation.Server.Client.Tests.csproj b/tests/Tgstation.Server.Client.Tests/Tgstation.Server.Client.Tests.csproj
index c2c09fe7b87..0e74bf0b36b 100644
--- a/tests/Tgstation.Server.Client.Tests/Tgstation.Server.Client.Tests.csproj
+++ b/tests/Tgstation.Server.Client.Tests/Tgstation.Server.Client.Tests.csproj
@@ -6,7 +6,7 @@
-
+
diff --git a/tests/Tgstation.Server.Host.Tests/Tgstation.Server.Host.Tests.csproj b/tests/Tgstation.Server.Host.Tests/Tgstation.Server.Host.Tests.csproj
index a0e5d2ba452..69c414d1e2e 100644
--- a/tests/Tgstation.Server.Host.Tests/Tgstation.Server.Host.Tests.csproj
+++ b/tests/Tgstation.Server.Host.Tests/Tgstation.Server.Host.Tests.csproj
@@ -7,7 +7,7 @@
-
+
diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs
index aff9e458671..df2476444b3 100644
--- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs
+++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs
@@ -586,13 +586,13 @@ async Task DumpTests(bool mini, CancellationToken cancellationToken)
// these can also happen
if (!(new PlatformIdentifier().IsWindows
- && (job.ExceptionDetails.Contains("BetterWin32Errors.Win32Exception: E_ACCESSDENIED: Access is denied.")
- || job.ExceptionDetails.Contains("BetterWin32Errors.Win32Exception: E_HANDLE: The handle is invalid.")
- || job.ExceptionDetails.Contains("BetterWin32Errors.Win32Exception: 3489660936: Unknown error (0xd0000008)")
- || job.ExceptionDetails.Contains("System.InvalidOperationException: No process is associated with this object.")
- || job.ExceptionDetails.Contains("BetterWin32Errors.Win32Exception: 2147942424: The program issued a command but the command length is incorrect.")
- || job.ExceptionDetails.Contains("BetterWin32Errors.Win32Exception: 2147942699: Only part of a ReadProcessMemory or WriteProcessMemory request was completed.")
- || job.ExceptionDetails.Contains("BetterWin32Errors.Win32Exception: 3489660964: Unknown error (0xd0000024)"))))
+ && (job.ExceptionDetails.Contains("Access is denied.")
+ || job.ExceptionDetails.Contains("The handle is invalid.")
+ || job.ExceptionDetails.Contains("Unknown error")
+ || job.ExceptionDetails.Contains("No process is associated with this object.")
+ || job.ExceptionDetails.Contains("The program issued a command but the command length is incorrect.")
+ || job.ExceptionDetails.Contains("Only part of a ReadProcessMemory or WriteProcessMemory request was completed.")
+ || job.ExceptionDetails.Contains("Unknown error"))))
break;
var restartJob = await instanceClient.DreamDaemon.Restart(cancellationToken);
diff --git a/tests/Tgstation.Server.Tests/Tgstation.Server.Tests.csproj b/tests/Tgstation.Server.Tests/Tgstation.Server.Tests.csproj
index e2651d56a29..84fb6104916 100644
--- a/tests/Tgstation.Server.Tests/Tgstation.Server.Tests.csproj
+++ b/tests/Tgstation.Server.Tests/Tgstation.Server.Tests.csproj
@@ -6,7 +6,7 @@
-
+
diff --git a/tgstation-server.sln b/tgstation-server.sln
index 31d15d01590..8815c70e786 100644
--- a/tgstation-server.sln
+++ b/tgstation-server.sln
@@ -197,13 +197,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ISSUE_TEMPLATE", "ISSUE_TEM
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tgstation.Server.Host.Tests.Signals", "tests\Tgstation.Server.Host.Tests.Signals\Tgstation.Server.Host.Tests.Signals.csproj", "{5813CC33-B16C-485D-A74D-20204DDF6542}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tgstation.Server.Migrator", "tools\Tgstation.Server.Migrator\Tgstation.Server.Migrator.csproj", "{CE499888-B22B-457C-891E-0EA9DC317228}"
- ProjectSection(ProjectDependencies) = postProject
- {07ED0FD5-E46B-4841-931D-BA2B673E16B2} = {07ED0FD5-E46B-4841-931D-BA2B673E16B2}
- EndProjectSection
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tgstation.Server.Migrator.Comms", "tools\Tgstation.Server.Migrator.Comms\Tgstation.Server.Migrator.Comms.csproj", "{07ED0FD5-E46B-4841-931D-BA2B673E16B2}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tgstation.Server.Host.Common", "src\Tgstation.Server.Host.Common\Tgstation.Server.Host.Common.csproj", "{CF3968A0-EA81-4464-B2D4-C7D40F6B5BCB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tgstation.Server.Common", "src\Tgstation.Server.Common\Tgstation.Server.Common.csproj", "{70CD9A98-D31A-44A4-81D1-D02764CEEEFD}"
@@ -274,6 +267,14 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tgstation.Server.Shared.Tes
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tgstation.Server.Client.GraphQL", "src\Tgstation.Server.Client.GraphQL\Tgstation.Server.Client.GraphQL.csproj", "{8BF95E2D-FD27-470C-82B7-C21AC01BFBD7}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "nix", "nix", "{5130526C-A553-493B-A9B0-3DB452949886}"
+ ProjectSection(SolutionItems) = preProject
+ build\package\nix\flake.nix = build\package\nix\flake.nix
+ build\package\nix\package.nix = build\package\nix\package.nix
+ build\package\nix\ServerConsole.sha256 = build\package\nix\ServerConsole.sha256
+ build\package\nix\tgstation-server.nix = build\package\nix\tgstation-server.nix
+ EndProjectSection
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -448,30 +449,6 @@ Global
{5813CC33-B16C-485D-A74D-20204DDF6542}.ReleaseNoWindows|Any CPU.Build.0 = Release|Any CPU
{5813CC33-B16C-485D-A74D-20204DDF6542}.ReleaseNoWix|Any CPU.ActiveCfg = Release|Any CPU
{5813CC33-B16C-485D-A74D-20204DDF6542}.ReleaseNoWix|Any CPU.Build.0 = Release|Any CPU
- {CE499888-B22B-457C-891E-0EA9DC317228}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {CE499888-B22B-457C-891E-0EA9DC317228}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {CE499888-B22B-457C-891E-0EA9DC317228}.DebugNoWindows|Any CPU.ActiveCfg = Debug|Any CPU
- {CE499888-B22B-457C-891E-0EA9DC317228}.DebugNoWindows|Any CPU.Build.0 = Debug|Any CPU
- {CE499888-B22B-457C-891E-0EA9DC317228}.DebugNoWix|Any CPU.ActiveCfg = Debug|Any CPU
- {CE499888-B22B-457C-891E-0EA9DC317228}.DebugNoWix|Any CPU.Build.0 = Debug|Any CPU
- {CE499888-B22B-457C-891E-0EA9DC317228}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {CE499888-B22B-457C-891E-0EA9DC317228}.Release|Any CPU.Build.0 = Release|Any CPU
- {CE499888-B22B-457C-891E-0EA9DC317228}.ReleaseNoWindows|Any CPU.ActiveCfg = Release|Any CPU
- {CE499888-B22B-457C-891E-0EA9DC317228}.ReleaseNoWindows|Any CPU.Build.0 = Release|Any CPU
- {CE499888-B22B-457C-891E-0EA9DC317228}.ReleaseNoWix|Any CPU.ActiveCfg = Release|Any CPU
- {CE499888-B22B-457C-891E-0EA9DC317228}.ReleaseNoWix|Any CPU.Build.0 = Release|Any CPU
- {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.DebugNoWindows|Any CPU.ActiveCfg = Debug|Any CPU
- {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.DebugNoWindows|Any CPU.Build.0 = Debug|Any CPU
- {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.DebugNoWix|Any CPU.ActiveCfg = Debug|Any CPU
- {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.DebugNoWix|Any CPU.Build.0 = Debug|Any CPU
- {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.Release|Any CPU.Build.0 = Release|Any CPU
- {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.ReleaseNoWindows|Any CPU.ActiveCfg = Release|Any CPU
- {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.ReleaseNoWindows|Any CPU.Build.0 = Release|Any CPU
- {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.ReleaseNoWix|Any CPU.ActiveCfg = Release|Any CPU
- {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.ReleaseNoWix|Any CPU.Build.0 = Release|Any CPU
{CF3968A0-EA81-4464-B2D4-C7D40F6B5BCB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CF3968A0-EA81-4464-B2D4-C7D40F6B5BCB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CF3968A0-EA81-4464-B2D4-C7D40F6B5BCB}.DebugNoWindows|Any CPU.ActiveCfg = Debug|Any CPU
@@ -605,8 +582,6 @@ Global
{103C61AB-67D6-46FE-AA47-CC633B88EE0F} = {82066812-6C73-4360-943B-B23F2F491261}
{CFFD7992-E73A-4D1F-9D7A-C817C07B7BEB} = {E82104F4-F5C4-4786-ACD4-B635166CDB21}
{5813CC33-B16C-485D-A74D-20204DDF6542} = {316141B0-CD21-4769-A013-D53DA9B9EC09}
- {CE499888-B22B-457C-891E-0EA9DC317228} = {A55C1117-5808-4AB2-BEA6-4D4A3E66A2F2}
- {07ED0FD5-E46B-4841-931D-BA2B673E16B2} = {A55C1117-5808-4AB2-BEA6-4D4A3E66A2F2}
{2648A85F-61AE-428E-95E1-66D06C7A3768} = {6FF654E6-3E2C-46D4-872D-D528F77D6973}
{457A1F89-6201-4430-BCC6-2F4438A54B9E} = {2648A85F-61AE-428E-95E1-66D06C7A3768}
{08E7C650-A447-4DE2-974E-ED123B50F8D6} = {457A1F89-6201-4430-BCC6-2F4438A54B9E}
@@ -619,6 +594,7 @@ Global
{69944039-65C2-40E1-9D86-0608FA0C2D70} = {A55C1117-5808-4AB2-BEA6-4D4A3E66A2F2}
{7F7FCFDF-271D-45C2-830C-BCCB19C57077} = {A55C1117-5808-4AB2-BEA6-4D4A3E66A2F2}
{EAB84FD0-5514-4254-B188-7D90ACB7284D} = {316141B0-CD21-4769-A013-D53DA9B9EC09}
+ {5130526C-A553-493B-A9B0-3DB452949886} = {2648A85F-61AE-428E-95E1-66D06C7A3768}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {DFD36C95-3E49-41C7-ACDB-86BAF5B18A79}
diff --git a/tools/Tgstation.Server.LogoGenerator/Program.cs b/tools/Tgstation.Server.LogoGenerator/Program.cs
index 2ec845f18d5..820084663a1 100644
--- a/tools/Tgstation.Server.LogoGenerator/Program.cs
+++ b/tools/Tgstation.Server.LogoGenerator/Program.cs
@@ -3,6 +3,7 @@
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
+using System.Runtime.InteropServices;
using System.Text;
using Svg;
@@ -25,7 +26,45 @@
using var bitmap = svg.Draw(128, 128);
using var whiteBgBitmap = whiteBgSvg.Draw(160, 160);
-using var icon = Icon.FromHandle(whiteBgBitmap.GetHicon());
+// https://stackoverflow.com/questions/21387391/how-to-convert-an-image-to-an-icon-without-losing-transparency/21389253#21389253
+// slight modifications
+static Icon IconFromImage(Image img)
+{
+ using var ms = new MemoryStream();
+ using var bw = new BinaryWriter(ms);
+ // Header
+ bw.Write((short)0); // 0 : reserved
+ bw.Write((short)1); // 2 : 1=ico, 2=cur
+ bw.Write((short)1); // 4 : number of images
+ // Image directory
+ var w = img.Width;
+ if (w >= 256) throw new InvalidOperationException("Width too big!");
+ bw.Write((byte)w); // 0 : width of image
+ var h = img.Height;
+ if (h >= 256) throw new InvalidOperationException("Height too big!");
+ bw.Write((byte)h); // 1 : height of image
+ bw.Write((byte)0); // 2 : number of colors in palette
+ bw.Write((byte)0); // 3 : reserved
+ bw.Write((short)0); // 4 : number of color planes
+ bw.Write((short)0); // 6 : bits per pixel
+ var sizeHere = ms.Position;
+ bw.Write(0); // 8 : image size
+ var start = (int)ms.Position + 4;
+ bw.Write(start); // 12: offset of image data
+ // Image data
+ img.Save(ms, ImageFormat.Png);
+ var imageSize = (int)ms.Position - start;
+ ms.Seek(sizeHere, SeekOrigin.Begin);
+ bw.Write(imageSize);
+ ms.Seek(0, SeekOrigin.Begin);
+
+ // And load it
+ return new Icon(ms);
+}
+
+using var icon = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
+ ? IconFromImage(whiteBgBitmap)
+ : Icon.FromHandle(whiteBgBitmap.GetHicon());
Directory.CreateDirectory("artifacts");
await using var iconStream = new FileStream("artifacts/tgs.ico", FileMode.Create);
diff --git a/tools/Tgstation.Server.Migrator.Comms/Program.cs b/tools/Tgstation.Server.Migrator.Comms/Program.cs
deleted file mode 100644
index 3c46d8a1cca..00000000000
--- a/tools/Tgstation.Server.Migrator.Comms/Program.cs
+++ /dev/null
@@ -1,389 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Net.Http.Headers;
-using System.Reflection;
-using System.Text;
-using System.Threading.Tasks;
-
-using TGS.Interface;
-
-using Tgstation.Server.Api;
-using Tgstation.Server.Api.Models;
-using Tgstation.Server.Api.Models.Internal;
-using Tgstation.Server.Api.Models.Request;
-using Tgstation.Server.Client;
-using Tgstation.Server.Common.Extensions;
-
-static class Program
-{
- static async Task Main(string[] args)
- {
- try
- {
- var tgs3Client = new Client();
-
- switch (args[0])
- {
- case "--verify-connection":
- var status = tgs3Client.ConnectionStatus(out var error);
- if (status != ConnectivityLevel.Administrator)
- {
- Console.WriteLine($"Connection Error: {error}");
- return 3;
- }
- return 0;
- case "--migrate":
- ushort apiPort = ushort.Parse(args[1]);
- return await Migrate(tgs3Client, apiPort);
- default:
- return 2;
- }
- }
- catch (Exception ex)
- {
- Console.WriteLine(ex);
- return 1;
- }
- }
-
- static async Task Migrate(IClient tgs3Client, ushort apiPort)
- {
-#if DEBUG
- Console.WriteLine("Test log line...");
- System.Diagnostics.Debugger.Launch();
-#endif
- Console.WriteLine("Connecting to TGS3...");
- var status = tgs3Client.ConnectionStatus(out var tgs3Error);
- if (status != ConnectivityLevel.Administrator)
- {
- Console.WriteLine($"Connection Error: {tgs3Client}");
- return 13;
- }
-
- Console.WriteLine("Connected!");
-
- Console.WriteLine("Connecting to TGS6...");
- var assemblyName = Assembly.GetExecutingAssembly().GetName();
- var productInfoHeaderValue =
- new ProductInfoHeaderValue(
- assemblyName.Name!,
- assemblyName.Version!.Semver().ToString());
-
- var serverUrl = new Uri($"http://localhost:{apiPort}");
- var clientFactory = new RestServerClientFactory(productInfoHeaderValue.Product);
- var TGS6Client = await clientFactory.CreateFromLogin(
- serverUrl,
- DefaultCredentials.AdminUserName,
- DefaultCredentials.DefaultAdminUserPassword);
-
- Console.WriteLine("Connected!");
-
- // we do this synchronously and patiently because we aren't chumbii and this is delicate
- // We need clear logs
- var tgs3Instances = tgs3Client.Server.Instances.ToList();
- foreach (var tgs3Instance in tgs3Instances)
- {
- var instanceName = tgs3Instance.Metadata.Name;
- var instancePath = tgs3Instance.Metadata.Path;
-
- if (!tgs3Instance.Metadata.Enabled)
- {
- Console.WriteLine($"Skipping instance {instanceName} at {instancePath}. Disabled.");
- continue;
- }
-
- Console.WriteLine($"Migrating instance {instanceName} at {instancePath}");
-
- RepositoryUpdateRequest? repositoryUpdateRequest = null;
- if (tgs3Instance.Repository.Exists())
- {
- Console.WriteLine("Gathering instance repository data...");
- repositoryUpdateRequest = new RepositoryUpdateRequest
- {
- CommitterEmail = tgs3Instance.Repository.GetCommitterEmail(),
- CommitterName = tgs3Instance.Repository.GetCommitterName(),
- UpdateSubmodules = true, // default in 3
- Reference = tgs3Instance.Repository.GetBranch(out tgs3Error),
- };
-
- if (tgs3Error != null)
- {
- Console.WriteLine($"Error retrieving current branch: {tgs3Error}");
- }
- }
- else
- Console.WriteLine("Instance has no repository, that's fine.");
-
- Console.WriteLine("Gather DreamDaemon and DreamMaker data...");
- var dreamDaemonRequest = new DreamDaemonRequest
- {
- AllowWebClient = tgs3Instance.DreamDaemon.Webclient(),
- AutoStart = tgs3Instance.DreamDaemon.Autostart(),
- Port = tgs3Instance.DreamDaemon.Port(),
- SecurityLevel = tgs3Instance.DreamDaemon.SecurityLevel() switch
- {
- TGS.Interface.DreamDaemonSecurity.Safe => Tgstation.Server.Api.Models.DreamDaemonSecurity.Safe,
- TGS.Interface.DreamDaemonSecurity.Ultrasafe => Tgstation.Server.Api.Models.DreamDaemonSecurity.Ultrasafe,
- _ => Tgstation.Server.Api.Models.DreamDaemonSecurity.Trusted,
- }
- };
-
- var dreamMakerRequest = new DreamMakerRequest
- {
- ApiValidationSecurityLevel = dreamDaemonRequest.SecurityLevel,
- ApiValidationPort = (ushort)(dreamDaemonRequest.Port + 111) // Best rotation we can do...
- };
-
- Console.WriteLine("Gathering chat data...");
- var providerInfos = tgs3Instance.Chat.ProviderInfos();
- var chatBotCreateRequests = new List();
- foreach(var providerInfo in providerInfos)
- {
- if (!providerInfo.Enabled)
- continue;
-
- var createRequest = new ChatBotCreateRequest()
- {
- Provider = providerInfo.Provider switch
- {
- TGS.Interface.ChatProvider.Discord => Tgstation.Server.Api.Models.ChatProvider.Discord,
- _ => Tgstation.Server.Api.Models.ChatProvider.Irc,
- },
- Enabled = true,
- ReconnectionInterval = 5,
- };
-
- var isDiscordProvider = createRequest.Provider == Tgstation.Server.Api.Models.ChatProvider.Discord;
- createRequest.Name = isDiscordProvider
- ? "Discord Bot"
- : "IRC Bot";
-
- Console.WriteLine($"Gathering data for {createRequest.Name}...");
-
- ChatConnectionStringBuilder csb;
- if (createRequest.Provider == Tgstation.Server.Api.Models.ChatProvider.Discord)
- {
- var discordSetupInfo = new DiscordSetupInfo(providerInfo);
- csb = new DiscordConnectionStringBuilder
- {
- DMOutputDisplay = DiscordDMOutputDisplayType.Always,
- BotToken = discordSetupInfo.BotToken
- };
-
- }
- else
- {
- var ircSetupInfo = new IRCSetupInfo(providerInfo);
- csb = new IrcConnectionStringBuilder
- {
- Address = ircSetupInfo.URL,
- Nickname = ircSetupInfo.Nickname,
- Port = ircSetupInfo.Port
- };
- }
- createRequest.ConnectionString = csb.ToString();
-
- createRequest.Channels = new List();
-
- static string NormalizeChannelId(string channelId) => channelId.ToLowerInvariant().Trim();
-
- var distinctChannels = providerInfo.WatchdogChannels
- .Union(providerInfo.DevChannels)
- .Union(providerInfo.AdminChannels)
- .Union(providerInfo.GameChannels)
- .Select(NormalizeChannelId)
- .Distinct();
-
- foreach(var channelIdentifier in distinctChannels)
- {
- var newChatChannel = new ChatChannel
- {
- IsWatchdogChannel = providerInfo.WatchdogChannels.Any(x => NormalizeChannelId(x) == channelIdentifier),
- IsAdminChannel = providerInfo.AdminChannels.Any(x => NormalizeChannelId(x) == channelIdentifier),
- IsUpdatesChannel = providerInfo.DevChannels.Any(x => NormalizeChannelId(x) == channelIdentifier),
- // system channels are too new a feature to target
- ChannelData = channelIdentifier,
- };
-
- createRequest.Channels.Add(newChatChannel);
- }
-
- chatBotCreateRequests.Add(createRequest);
- }
-
- Console.WriteLine("Detaching TGS3 instance...");
- tgs3Client.Server.InstanceManager.DetachInstance(instanceName);
-
- Console.WriteLine("Creating TGS6 attach file...");
- File.WriteAllText(Path.Combine(instancePath, "TGS4_ALLOW_INSTANCE_ATTACH"), String.Empty);
-
- Console.WriteLine("Checking BYOND install...");
- var byondDirectory = Path.Combine(instancePath, "BYOND");
- var byondVersionFile = Path.Combine(byondDirectory, "byond_version.dat");
-
- EngineVersionRequest? byondVersionRequest = null;
- if (Directory.Exists(byondDirectory) && File.Exists(byondVersionFile))
- {
- var byondVersion = Version.Parse(File.ReadAllText(byondVersionFile).Trim());
- Console.WriteLine($"Found installed BYOND version: {byondVersion.Major}.{byondVersion.Minor}");
- byondVersionRequest = new EngineVersionRequest
- {
- EngineVersion = new EngineVersion
- {
- Version = byondVersion
- }
- };
- }
-
- var oldStaticDirectory = Path.Combine(instancePath, "Static");
- var newConfigurationDirectory = Path.Combine(instancePath, "Configuration");
- if (Directory.Exists(oldStaticDirectory))
- {
- Console.WriteLine("Migrating Static to Configuration/GameStaticFiles");
- var gameStaticFilesDirectory = Path.Combine(newConfigurationDirectory, "GameStaticFiles");
- Directory.CreateDirectory(newConfigurationDirectory);
- Directory.Move(oldStaticDirectory, gameStaticFilesDirectory);
-
- Console.WriteLine("Moving code modifications...");
- var codeModsDirectory = Path.Combine(newConfigurationDirectory, "CodeModifications");
- Directory.CreateDirectory(codeModsDirectory);
-
- var allDmFiles = Directory.EnumerateFiles(gameStaticFilesDirectory, "*.dm", SearchOption.TopDirectoryOnly).ToList();
- foreach (var dmFile in allDmFiles)
- {
- File.Move(Path.Combine(gameStaticFilesDirectory, dmFile), Path.Combine(codeModsDirectory, Path.GetFileName(dmFile)));
- }
-
- var allDmeFiles = Directory.EnumerateFiles(gameStaticFilesDirectory, "*.dme", SearchOption.TopDirectoryOnly).ToList();
- if (allDmeFiles.Any())
- {
- foreach (var dmeFile in allDmeFiles)
- {
- File.Move(Path.Combine(gameStaticFilesDirectory, dmeFile), Path.Combine(codeModsDirectory, Path.GetFileName(dmeFile)));
- }
- }
- else if (allDmFiles.Any())
- {
- Console.WriteLine("Generating HeadInclude.dm...");
- var headIncludeBuilder = new StringBuilder();
- foreach (var dmFile in allDmFiles.OrderBy(fileName => fileName.ToUpperInvariant()))
- {
- headIncludeBuilder.Append("#include \"");
- headIncludeBuilder.Append(Path.GetFileName(dmFile));
- headIncludeBuilder.Append("\"");
- headIncludeBuilder.Append(Environment.NewLine);
- }
-
- File.WriteAllText(Path.Combine(codeModsDirectory, "HeadInclude.dm"), headIncludeBuilder.ToString());
- }
- }
-
- var eventHandlersDirectory = Path.Combine(instancePath, "EventHandlers");
- if (Directory.Exists(eventHandlersDirectory))
- {
- Console.WriteLine("Moving event scripts...");
- Directory.CreateDirectory(newConfigurationDirectory);
- Directory.Move(eventHandlersDirectory, Path.Combine(newConfigurationDirectory, "EventScripts"));
- }
-
- var diagnosticsDirectory = Path.Combine(instancePath, "Diagnostics");
- var minidumpsDirectory = Path.Combine(diagnosticsDirectory, "Minidumps");
- if (Directory.Exists(minidumpsDirectory))
- {
- Console.WriteLine("Renaming Minidumps folder to ProcessDumps...");
- Directory.Move(minidumpsDirectory, Path.Combine(diagnosticsDirectory, "ProcessDumps"));
- }
-
- Console.WriteLine("Deleting BYOND folder...");
- await RecursivelyDeleteDirectory(new DirectoryInfo(byondDirectory));
- Console.WriteLine("Deleting RepoKey folder...");
- await RecursivelyDeleteDirectory(new DirectoryInfo(Path.Combine(instancePath, "RepoKey")));
- Console.WriteLine("Deleting Game folder...");
- await RecursivelyDeleteDirectory(new DirectoryInfo(Path.Combine(instancePath, "Game")));
- Console.WriteLine("Deleting Instance.json...");
- File.Delete(Path.Combine(instancePath, "Instance.json"));
- Console.WriteLine("Deleting prtestjob.json...");
- File.Delete(Path.Combine(instancePath, "prtestjob.json"));
- Console.WriteLine("Deleting TGS3.json...");
- File.Delete(Path.Combine(instancePath, "TGS3.json"));
- Console.WriteLine("Deleting TGDreamDaemonBridge.dll...");
- File.Delete(Path.Combine(instancePath, "TGDreamDaemonBridge.dll"));
-
- Console.WriteLine("Attaching TGS6 instance...");
- var TGS6Instance = await TGS6Client.Instances.CreateOrAttach(new InstanceCreateRequest
- {
- ConfigurationType = ConfigurationType.Disallowed,
- Name = instanceName,
- Path = instancePath,
- }, default);
-
- Console.WriteLine($"Onlining TGS6 instance ID {TGS6Instance.Id}...");
- TGS6Instance = await TGS6Client.Instances.Update(new InstanceUpdateRequest
- {
- Online = true,
- Id = TGS6Instance.Id
- }, default);
-
- var v5InstanceClient = TGS6Client.Instances.CreateClient(TGS6Instance);
-
- if (byondVersionRequest != null)
- {
- Console.WriteLine("Triggering BYOND install job...");
- await v5InstanceClient.Engine.SetActiveVersion(byondVersionRequest, null, default);
- }
-
- if (repositoryUpdateRequest != null)
- {
- Console.WriteLine("Updating repository settings...");
- await v5InstanceClient.Repository.Update(repositoryUpdateRequest, default);
- }
-
- Console.WriteLine("Updating deployment settings...");
- await v5InstanceClient.DreamMaker.Update(dreamMakerRequest, default);
-
- Console.WriteLine("Updating DreamDaemon settings...");
- await v5InstanceClient.DreamDaemon.Update(dreamDaemonRequest, default);
-
- foreach(var chatBotCreateRequest in chatBotCreateRequests)
- {
- Console.WriteLine($"Creating chat bot {chatBotCreateRequest.Name}...");
- await v5InstanceClient.ChatBots.Create(chatBotCreateRequest, default);
- }
-
- Console.WriteLine($"Instance {instanceName} (TGS6 ID: {TGS6Instance.Id}) successfully migrated!");
- }
-
- Console.WriteLine("All enabled V3 instances migrated into V5 and detached from V3!");
-
- return 0;
- }
-
- static async Task RecursivelyDeleteDirectory(DirectoryInfo dir)
- {
- var tasks = new List();
-
- if (!dir.Exists)
- return;
-
- // check if we are a symbolic link
- if (!dir.Attributes.HasFlag(FileAttributes.Directory) || dir.Attributes.HasFlag(FileAttributes.ReparsePoint))
- {
- dir.Delete();
- return;
- }
-
- foreach (var subDir in dir.EnumerateDirectories())
- tasks.Add(RecursivelyDeleteDirectory(subDir));
-
- foreach (var file in dir.EnumerateFiles())
- {
- file.Attributes = FileAttributes.Normal;
- file.Delete();
- }
-
- await Task.WhenAll(tasks);
- dir.Delete(true);
- }
-}
diff --git a/tools/Tgstation.Server.Migrator.Comms/Tgstation.Server.Migrator.Comms.csproj b/tools/Tgstation.Server.Migrator.Comms/Tgstation.Server.Migrator.Comms.csproj
deleted file mode 100644
index e43af6ce0f6..00000000000
--- a/tools/Tgstation.Server.Migrator.Comms/Tgstation.Server.Migrator.Comms.csproj
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- Exe
- net472
- win-x86
- $(TgsMigratorVersion)
- enable
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/tools/Tgstation.Server.Migrator/Program.cs b/tools/Tgstation.Server.Migrator/Program.cs
deleted file mode 100644
index 86cabd419e5..00000000000
--- a/tools/Tgstation.Server.Migrator/Program.cs
+++ /dev/null
@@ -1,544 +0,0 @@
-using System;
-using System.Collections.Specialized;
-using System.ComponentModel;
-using System.Configuration.Install;
-using System.Diagnostics;
-using System.Diagnostics.CodeAnalysis;
-using System.IO;
-using System.Linq;
-using System.Management;
-using System.Net.Http;
-using System.Net.Http.Headers;
-using System.Reflection;
-using System.Security.Principal;
-using System.ServiceProcess;
-using System.Text.RegularExpressions;
-using System.Threading.Tasks;
-
-using Microsoft.Extensions.Logging;
-
-using Octokit;
-
-using Tgstation.Server.Api;
-using Tgstation.Server.Client;
-using Tgstation.Server.Common;
-using Tgstation.Server.Common.Extensions;
-using Tgstation.Server.Common.Http;
-using Tgstation.Server.Host.IO;
-using Tgstation.Server.Host.Setup;
-using Tgstation.Server.Migrator.Properties;
-
-using FileMode = System.IO.FileMode;
-
-[DoesNotReturn]
-static void ExitPause(int exitCode)
-{
- Console.WriteLine("Consider saving the console text to report issues. Press any key to exit...");
- Console.ReadKey();
- Environment.Exit(exitCode);
-}
-
-try
-{
- var commandLine = Environment.GetCommandLineArgs();
- var commandLineArguments = commandLine.Skip(1);
- var skipPreamble = commandLineArguments.Any(x => x.Equals("--skip-preamble", StringComparison.OrdinalIgnoreCase));
-
- Console.WriteLine("This is a very straightfoward script to migrate the instances of a TGS3 install into a new TGS6 install");
-
- static bool PromptYesOrNo(string question)
- {
- Console.Write($"{question} (y/n):");
- var character = Console.ReadKey();
- Console.WriteLine();
- return character.KeyChar.ToString().ToUpperInvariant() == "Y";
- }
-
- // WORKING DIRECTORY CHECK
- var currentAssembly = Assembly.GetExecutingAssembly();
- if(Path.GetDirectoryName(Path.GetFullPath(currentAssembly.Location))!.Replace("\\", "/").ToUpperInvariant()
- != Path.GetFullPath(Environment.CurrentDirectory).Replace("\\", "/").ToUpperInvariant())
- {
- Console.WriteLine("Please keep the working directory equivalent to the program directory for this migration!");
- ExitPause(8);
- }
-
- // PREREQUISITE CHECK
- if (!skipPreamble)
- {
- Console.WriteLine("We need to ensure you're running this program as Administrator because there are several operations we'll do that require it.");
- Console.WriteLine("If not, you will be prompted to elevate this process.");
- }
-
- // ADMINISTRATOR CHECK
- static bool IsAdministrator()
- {
- using var identity = WindowsIdentity.GetCurrent();
- var principal = new WindowsPrincipal(identity);
- return principal.IsInRole(WindowsBuiltInRole.Administrator);
- }
-
- if (!IsAdministrator())
- {
- Console.WriteLine("Not running as admin. Elevating process...");
- var selfExecutable = commandLine.First().Replace(".dll", ".exe");
- var selfArguments = String.Join(" ", commandLineArguments) + " --skip-preamble";
- using var elevatedProcess = new Process();
- elevatedProcess.StartInfo.UseShellExecute = true;
- elevatedProcess.StartInfo.FileName = selfExecutable;
- elevatedProcess.StartInfo.Arguments = selfArguments;
- elevatedProcess.StartInfo.Verb = "runas";
-
- elevatedProcess.Start();
- return;
- }
-
- Console.WriteLine("Administrative privileges confirmed.");
-
- // TGS3 SERVICE CHECK
-
- const string PathToCommsBinary =
-#if DEBUG
- "../../../../../Tgstation.Server.Migrator.Comms/bin/Debug/net472/win-x86/" +
-#else
- "Comms/" +
-#endif
- "Tgstation.Server.Migrator.Comms.exe";
-
- Console.WriteLine($"Checking {PathToCommsBinary} exists...");
- if (!File.Exists(PathToCommsBinary))
- {
- Console.WriteLine("Could not find WCF comms binary!");
- ExitPause(7);
- }
-
- static int RunComms(string command)
- {
- using var commsProcess = new Process();
- commsProcess.StartInfo.FileName = PathToCommsBinary;
- commsProcess.StartInfo.Arguments = command;
- commsProcess.Start();
- commsProcess.WaitForExit();
- return commsProcess.ExitCode;
- }
-
- Console.WriteLine("Checking for TGS3 service...");
- const string OldServiceName = "TG Station Server";
- const string NewServiceName = Constants.CanonicalPackageName;
-
- static ServiceController GetTgs3Service(bool checkNewOneIsntInstalled)
- {
- var allServices = ServiceController.GetServices();
- var tgs3Service = allServices.FirstOrDefault(service => service.ServiceName == OldServiceName);
- foreach (var service in allServices)
- {
- if (service == tgs3Service)
- continue;
-
- using (service)
- if (checkNewOneIsntInstalled && (service.ServiceName == NewServiceName || service.ServiceName == "tgstation-server-4"))
- {
- Console.WriteLine("Detected existing TGS4+ install! Cannot continue. Please uninstall any versions of TGS4+ before continuing.");
- ExitPause(10);
- }
- }
-
- if (checkNewOneIsntInstalled)
- Console.WriteLine("TGS4+ service install not detected.");
-
- if (tgs3Service == null)
- {
- Console.WriteLine("TGS3 is not installed on this machine!");
- ExitPause(5);
- }
-
- return tgs3Service;
- }
-
- using var tgs3Service = GetTgs3Service(true);
-
- if (tgs3Service.Status != ServiceControllerStatus.Running)
- {
- Console.WriteLine("TGS3 service is installed but not running! Please start the service before continuing.");
- ExitPause(9);
- }
-
- // TGS3 CONNECTION CHECK
- Console.WriteLine("Checking TGS3 connection...");
- var commsExitCode = RunComms("--verify-connection");
- if(commsExitCode != 0)
- {
- Console.WriteLine("Could not connect to TGS3 as administrator!");
- ExitPause(6);
- }
-
- // USER INPUT
- Console.WriteLine("We've confirmed you have have both TGS3 installed and TGS4+ service UNinstalled on THIS machine.");
- Console.WriteLine();
- Console.WriteLine("Please read all of the following CAREFULLY before proceeding:");
- Console.WriteLine("Confirm you want to migrate to the latest version installing the necessary prerequisite .NET version along the way.");
- Console.WriteLine("Please note that this is a one way upgrade and will not keep your DreamDaemon servers running throughout it.");
- Console.WriteLine("All TGS3 instances will be migrated in place. The following components will be preserved:");
- Console.WriteLine("- Repository (No test merge data or SSH key)");
- Console.WriteLine("- BYOND version (redownloaded from byond.com)");
- Console.WriteLine("- A FEW server configuration settings (Committer info, Autostart, Webclient, Game Port, Security Level)");
- Console.WriteLine("- EventHandlers");
- Console.WriteLine("- Chat Bots, if enabled");
- Console.WriteLine(" - TGS4+ doesn't support individual user/group identification. Admin channels will be used instead");
- Console.WriteLine(" - IRC authentication information cannot be copied and must be manually adjusted");
- Console.WriteLine("- Static Files");
- Console.WriteLine("- Code Modifications");
- Console.WriteLine("Remaining components such as logins, game builds, etc. can be recreated once the migration is complete.");
- Console.WriteLine("IMPORTANT NOTES:");
- Console.WriteLine("- INSTANCES CANNOT HAVE GAME PORTS OFFSET 111 UNITS FROM EACH OTHER OR HIGHER THAN 65423! WE AREN'T CORRECTING FOR THIS WHILE MIGRATING!");
- Console.WriteLine("- DISABLED INSTANCES WILL NOT BE MIGRATED! PLEASE ENABLE ALL INSTANCES YOU WISH TO MIGRATE BEFORE CONTINUING!");
- Console.WriteLine("- INSTANCE AUTO UPDATE CAN INTERFERE WITH THE MIGRATION! PLEASE DISABLE IT ON ALL INSTANCES BEING MIGRATED BEFORE CONTINUING!");
- Console.WriteLine("- DO NOT ATTEMPT TO USE TGS3 VIA NORMAL METHODS WHILE THIS MIGRATION IS TAKING PLACE OR YOU COULD CORRUPT YOUR DATA!");
- Console.WriteLine("Side note: You can skip the TGS6 setup wizard step by copying your premade appsettings.Production.yml file next to this .exe NOW.");
- if (!PromptYesOrNo("Proceed with upgrade?"))
- {
- Console.WriteLine("Prerequisite not met.");
- ExitPause(0);
- }
-
- string? tgsInstallPath = null;
- do
- {
- Console.WriteLine("Please enter the directory where you would like the TGS binaries installed.");
- Console.Write("This may be anywhere but should be empty: ");
- tgsInstallPath = Console.ReadLine();
- if (!String.IsNullOrWhiteSpace(tgsInstallPath))
- {
- if (!Path.IsPathRooted(tgsInstallPath))
- {
- Console.WriteLine("Please do not use a relative path for this. Enter the full path including the drive letter.");
- tgsInstallPath = null;
- }
- else if (Path.GetInvalidPathChars().Any(invalidChar => tgsInstallPath.Contains(invalidChar)))
- {
- Console.WriteLine("Invalid characters detected!");
- tgsInstallPath = null;
- }
- }
- }
- while (String.IsNullOrWhiteSpace(tgsInstallPath));
-
- Console.WriteLine("Attempting to create TGS install directory...");
- Directory.CreateDirectory(tgsInstallPath);
-
- // ASP.NET 8.0 RUNTIME CHECK
- Console.WriteLine("Next step, we need to ensure the ASP.NET Core 6 runtime is installed on your machine.");
- Console.WriteLine("We're going to download it for you.");
- Console.WriteLine("Yes, this program runs .NET 6, but it contains the entire runtime embedded into it. You will need a system-wide install for TGS.");
-
- var runtimeInstalled = true; // assume for now
- using (var dotnetRuntimeCheck = new Process())
- {
- dotnetRuntimeCheck.StartInfo.FileName = "C:/Program Files/dotnet/dotnet.exe";
- dotnetRuntimeCheck.StartInfo.Arguments = "--list-runtimes";
- dotnetRuntimeCheck.StartInfo.RedirectStandardOutput = true;
-
- try
- {
- dotnetRuntimeCheck.Start();
-
- dotnetRuntimeCheck.WaitForExit();
- }
- catch (Win32Exception ex) when (ex.NativeErrorCode == 2)
- {
- Console.WriteLine("Dotnet does not appear to be installed at all.");
- runtimeInstalled = false;
- }
-
- if (runtimeInstalled)
- {
- var versions = await dotnetRuntimeCheck.StandardOutput.ReadToEndAsync();
- var regex = new Regex("Microsoft\\.AspNetCore\\.App 8\\.0\\.[0-9]+");
-
- if (!regex.IsMatch(versions))
- runtimeInstalled = false;
- }
- }
-
- // ASP.NET 8.0 RUNTIME SETUP
- var assemblyName = currentAssembly.GetName();
- var productInfoHeaderValue =
- new ProductInfoHeaderValue(
- assemblyName.Name!,
- assemblyName.Version!.Semver().ToString());
- var httpClientFactory = new HttpClientFactory(productInfoHeaderValue);
- if (!runtimeInstalled)
- {
- // RUNTIME DONWLOAD
- Console.WriteLine("The version we are installing is the latest circa 26-09-2022, feel free to update it later if you want but that is not necessary.");
-
- var x64 = Environment.Is64BitOperatingSystem;
- var xSubstitution = x64 ? "64" : "86";
- Console.WriteLine($"Running on an x{xSubstitution} system.");
-
- var downloadUri = RuntimeDistributableAttribute.Instance.RuntimeDistributableUrl;
-
- var dotnetDownloadFilePath = $"dotnet-hosting-bundle-installer.exe";
-
- Console.WriteLine($"Downloading {downloadUri} to {Path.GetFullPath(dotnetDownloadFilePath)}...");
-
- using var httpClient = httpClientFactory.CreateClient();
- using var request = new HttpRequestMessage(HttpMethod.Get, downloadUri);
- var webRequestTask = httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, default);
- using var response = await webRequestTask;
- response.EnsureSuccessStatusCode();
- await using (var responseStream = await response.Content.ReadAsStreamAsync())
- {
- await using var fileStream = new FileStream(
- dotnetDownloadFilePath,
- FileMode.Create,
- FileAccess.Write,
- FileShare.ReadWrite | FileShare.Delete,
- 4096,
- FileOptions.Asynchronous | FileOptions.SequentialScan);
- await responseStream.CopyToAsync(fileStream);
- }
-
- // RUNTIME INSTALLATION
- Console.WriteLine("Runtime downloaded. Running silent installation...");
- bool silentInstallSuccess = true;
- using var silentInstallProcess = new Process();
- {
- silentInstallProcess.StartInfo.UseShellExecute = false;
- silentInstallProcess.StartInfo.FileName = dotnetDownloadFilePath;
- silentInstallProcess.StartInfo.Arguments = "/install /quiet /norestart";
- silentInstallProcess.Start();
- silentInstallProcess.WaitForExit();
-
- if (silentInstallProcess.ExitCode != 0)
- {
- Console.WriteLine("Silent installation failed! Please install the runtime interactively.");
- Console.WriteLine("Launching install dialog");
- silentInstallSuccess = false;
- }
- }
-
- if (!silentInstallSuccess)
- {
- using var installProcess = new Process();
- installProcess.StartInfo.FileName = dotnetDownloadFilePath;
- installProcess.Start();
- installProcess.WaitForExit();
-
- if (!PromptYesOrNo("Was the installation successful?"))
- {
- Console.WriteLine("Cannot continue without ASP.NET 8.0 runtime installed.");
- ExitPause(2);
- }
- }
- }
- else
- {
- Console.WriteLine("Runtime detected successfully. Continuing...");
- }
-
-
- // TGS6 ONLINE LOCATING
- Console.WriteLine("Now we're going to locate the latest version of the TGS service.");
- Console.WriteLine("(This migrator does not support the console runner, but you may switch the installation to it after completion)");
-
- Console.WriteLine("Determining latest version of TGS 5.X.X...");
-
- var gitHubClient = new GitHubClient(new Octokit.ProductHeaderValue(productInfoHeaderValue.Product!.Name, productInfoHeaderValue.Product.Version));
-
- string? gitHubPat = Environment.GetEnvironmentVariable("TGS_MIGRATOR_GITHUB_PAT");
- if (gitHubPat != null)
- gitHubClient.Credentials = new Credentials(gitHubPat);
-
- const int TgstationServerRepoId = 92952846;
-
- var allReleases = await gitHubClient.Repository.Release.GetAll(TgstationServerRepoId);
-
- const string VersionFiveTagPrefix = "tgstation-server-v5.";
- var allVersionFiveReleases = allReleases
- .Where(release => release.TagName.StartsWith(VersionFiveTagPrefix));
- var latestVersionFiveRelease = allVersionFiveReleases
- .OrderByDescending(release => Version.Parse(release.TagName[(VersionFiveTagPrefix.Length - 2)..]))
- .FirstOrDefault();
-
- if (latestVersionFiveRelease == null)
- {
- Console.WriteLine("Unable to determine latest version 5 release!");
- ExitPause(3);
- }
-
- Console.WriteLine($"Latest V5 version: {latestVersionFiveRelease.TagName}");
-
- var serverServiceAsset = latestVersionFiveRelease.Assets.FirstOrDefault(asset => asset.Name == "ServerService.zip");
- if (serverServiceAsset == null)
- {
- Console.WriteLine("Unable to determine ServerService.zip release asset!");
- ExitPause(4);
- }
-
- // TGS6 SETUP WIZARD
- Console.WriteLine("We are now going to run the TGS setup wizard to generate your new server configuration file.");
-
- var serverFactory = Tgstation.Server.Host.Core.Application.CreateDefaultServerFactory();
- _ = await serverFactory.CreateServer(new[] { $"General:SetupWizardMode={SetupWizardMode.Only}" }, null, default); // This is where the wizard actually runs
-
- // TGS6 DOWNLOAD AND UNZIP
- Console.WriteLine("Downloading TGS6...");
-
- using (var loggerFactory = LoggerFactory.Create(builder => { }))
- {
- BufferedFileStreamProvider tgsFiveZipBuffer;
- {
- var fileDownloader = new FileDownloader(httpClientFactory, loggerFactory.CreateLogger());
- await using var tgsFiveZipDownload = fileDownloader.DownloadFile(new Uri(serverServiceAsset.BrowserDownloadUrl), null);
- tgsFiveZipBuffer = new BufferedFileStreamProvider(
- await tgsFiveZipDownload.GetResult(default));
- }
-
- await using (tgsFiveZipBuffer)
- {
- Console.WriteLine("Unzipping TGS6...");
- await serverFactory.IOManager.ZipToDirectory(
- tgsInstallPath,
- await tgsFiveZipBuffer.GetResult(default),
- default);
- }
- }
-
- // TGS6 CONFIG SETUP
- const string ConfigurationFileName = "appsettings.Production.yml";
- Console.WriteLine("Extracting API port from configuration...");
- ushort configuredApiPort;
- {
- var configFileContents = await File.ReadAllTextAsync(ConfigurationFileName);
- var match = Regex.Match(configFileContents, "ApiPort: ([0-9]+)");
- if (!match.Success)
- {
- Console.WriteLine("Unable to extract ApiPort setting!");
- ExitPause(12);
- }
-
- configuredApiPort = ushort.Parse(match.Groups[1].Value);
- }
-
- Console.WriteLine("Moving configuration file from setup wizard to installation folder...");
- File.Copy(ConfigurationFileName, Path.Combine(tgsInstallPath, ConfigurationFileName));
-
- // TGS6 SERVICE SETUP
- Console.WriteLine("Installing TGS6 service...");
- using (var processInstaller = new ServiceProcessInstaller())
- using (var installer = new ServiceInstaller())
- {
- processInstaller.Account = ServiceAccount.LocalSystem;
-
- installer.Context = new InstallContext(
- "tgs-migrate-install.log",
- new string[]
- {
- $"assemblypath={Path.Combine(tgsInstallPath, "Tgstation.Server.Host.Service.exe")}"
- });
- installer.Description = "/tg/station 13 server running as a windows service";
- installer.DisplayName = "tgstation-server";
- installer.StartType = ServiceStartMode.Automatic;
- installer.ServicesDependedOn = new string[] { "Tcpip", "Dhcp", "Dnscache" };
- installer.ServiceName = NewServiceName;
- installer.Parent = processInstaller;
-
- var state = new ListDictionary();
- installer.Install(state);
- }
-
- Console.WriteLine("Starting TGS6 service...");
- var allServices = ServiceController.GetServices();
- using (var TGS6Service = allServices.FirstOrDefault(service => service.ServiceName == NewServiceName))
- {
- if (TGS6Service == null)
- {
- Console.WriteLine("Unable to locate newly installed TGS6 service!");
- ExitPause(11);
- }
-
- foreach (var service in allServices)
- {
- if (service == TGS6Service)
- continue;
-
- service.Dispose();
- }
-
- TGS6Service.Start();
- TGS6Service.WaitForStatus(ServiceControllerStatus.Running, TimeSpan.FromMinutes(2));
- }
-
- // TGS6 CLIENT CONNECTION
- const int MaxWaitMinutes = 5;
- Console.WriteLine($"Connecting to TGS6 (Max {MaxWaitMinutes} minute wait)...");
- var giveUpAt = DateTimeOffset.UtcNow.AddMinutes(MaxWaitMinutes);
-
- var serverUrl = new Uri($"http://localhost:{configuredApiPort}");
- var clientFactory = new RestServerClientFactory(productInfoHeaderValue.Product);
- IRestServerClient TGS6Client;
- for (var I = 1; ; ++I)
- {
- try
- {
- Console.WriteLine($"Attempt {I}...");
- TGS6Client = await clientFactory.CreateFromLogin(
- serverUrl,
- DefaultCredentials.AdminUserName,
- DefaultCredentials.DefaultAdminUserPassword);
- break;
- }
- catch (HttpRequestException)
- {
- //migrating, to be expected
- if (DateTimeOffset.UtcNow > giveUpAt)
- throw;
- await Task.Delay(TimeSpan.FromSeconds(1));
- }
- catch (ServiceUnavailableException)
- {
- // migrating, to be expected
- if (DateTimeOffset.UtcNow > giveUpAt)
- throw;
- await Task.Delay(TimeSpan.FromSeconds(1));
- }
- }
-
- Console.WriteLine("Successfully connected to TGS6!");
-
- // COMMS MIGRATION
- Console.WriteLine("Deferring to Comms binary to migrate instances...");
-
- commsExitCode = RunComms($"--migrate {configuredApiPort}");
- if (commsExitCode != 0)
- {
- Console.WriteLine("Could not connect to TGS3 as administrator!");
- ExitPause(commsExitCode);
- }
-
- // TGS3 SHUTDOWN
- Console.WriteLine("Shutting down TGS3 service...");
- tgs3Service.Stop();
- tgs3Service.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromMinutes(2));
- tgs3Service.Dispose();
-
- Console.WriteLine("Disabling TGS3 service...");
- using (var managementObject = new ManagementObject(string.Format("Win32_Service.Name=\"{0}\"", OldServiceName)))
- {
- managementObject.InvokeMethod("ChangeStartMode", new object[] { "Disabled" });
- }
-
- if(tgs3Service.StartType != ServiceStartMode.Disabled)
- Console.WriteLine("Failed to disable TGS3 service! This isn't critical, however.");
-
- Console.WriteLine("Migration complete! Please continue uninstall TGS3 using Add/Remove Programs.");
- Console.WriteLine("Then configure TGS6 using an interactive client to build and start your server.");
- ExitPause(0);
-}
-catch (Exception ex)
-{
- Console.WriteLine("An error occurred in the migration!");
- Console.WriteLine(ex);
- ExitPause(1);
-}
diff --git a/tools/Tgstation.Server.Migrator/Properties/RuntimeDistributableAttribute.cs b/tools/Tgstation.Server.Migrator/Properties/RuntimeDistributableAttribute.cs
deleted file mode 100644
index d4434c61bb6..00000000000
--- a/tools/Tgstation.Server.Migrator/Properties/RuntimeDistributableAttribute.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-using System;
-using System.Reflection;
-
-namespace Tgstation.Server.Migrator.Properties
-{
- ///
- /// Attribute for bringing in the runtime redistributable download link
- ///
- [AttributeUsage(AttributeTargets.Assembly)]
- sealed class RuntimeDistributableAttribute : Attribute
- {
- ///
- /// Return the 's instance of the .
- ///
- public static RuntimeDistributableAttribute Instance => Assembly
- .GetExecutingAssembly()
- .GetCustomAttribute()!;
-
- ///
- /// The of the current runtime distributable.
- ///
- public Uri RuntimeDistributableUrl { get; }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The value of .
- public RuntimeDistributableAttribute(
- string runtimeDistributableUrl)
- {
- RuntimeDistributableUrl = new Uri(runtimeDistributableUrl ?? throw new ArgumentNullException(nameof(runtimeDistributableUrl)));
- }
- }
-}
diff --git a/tools/Tgstation.Server.Migrator/Tgstation.Server.Migrator.csproj b/tools/Tgstation.Server.Migrator/Tgstation.Server.Migrator.csproj
deleted file mode 100644
index 2511e50c18c..00000000000
--- a/tools/Tgstation.Server.Migrator/Tgstation.Server.Migrator.csproj
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
- Exe
- $(TgsFrameworkVersion)
- win-x86
- true
- $(TgsMigratorVersion)
- enable
- CA1416
- false
-
-
-
-
-
-
-
-
-
-
- <_Parameter1>$(TgsDotnetRedistUrl)
-
-
-
-
-
-
-
-
-
-
-
-
-
-